📄 connection.c
字号:
/***********************************************************Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights ReservedPermission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and thatboth that copyright notice and this permission notice appear in supporting documentation, and that the names of Digital or MIT not beused in advertising or publicity pertaining to distribution of thesoftware without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDINGALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALLDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ORANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THISSOFTWARE.******************************************************************//* $XConsortium: connection.c,v 1.88 88/10/22 22:06:31 keith Exp $ *//***************************************************************** * Stuff to create connections --- OS dependent * * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets, * CloseDownConnection, CheckConnections, AddEnabledDevice, * RemoveEnabledDevice, OnlyListToOneClient, * ListenToAllClients, * * (WaitForSomething is in its own file) * * In this implementation, a client socket table is not kept. * Instead, what would be the index into the table is just the * file descriptor of the socket. This won't work for if the * socket ids aren't small nums (0 - 2^8) * *****************************************************************/#ifdef ISOCONN#include <math.h>#endif /* ISOCONN */#include <dbm.h>#undef NULL#include "X.h"#include "Xproto.h"#include <sys/param.h>#include <errno.h>#include "Xos.h" /* for strings, file, time */#include <sys/socket.h>#include <signal.h>#include <fcntl.h>#include <setjmp.h>#ifdef hpux#include <sys/ioctl.h>#endif#ifdef TCPCONN#include <netinet/in.h>#ifndef hpux#include <netinet/tcp.h>#endif#endif#ifdef UNIXCONN/* * sites should be careful to have separate /tmp directories for diskless nodes */#include <sys/un.h>#include <sys/stat.h>static int unixDomainConnection = -1;#endif#include <stdio.h>#include <sys/uio.h>#include "osstruct.h"#include "osdep.h"#include "opaque.h"#include "dixstruct.h"#ifdef DNETCONN#include <netdnet/dn.h>#endif /* DNETCONN */#ifdef ISOCONN#include <isode/psap.h>#include <isode/tsap.h>#include <isode/isoservent.h>extern char *isodetcpath; #ifdef ISODEBUG/* * Set to true for loads of TSAP messages... */int isodexbug = FALSE;#endif /* ISODEBUG *//* * array of fd 2 family map so we can lookup right function below... * Its initialised at connection setup... */int fd2family[MAXSOCKS];/* * Globals for storing functions appropos each fd/socket type * UNIX_IO (0) map to sys calls * ISODE_IO (1) maps to my fns... */extern int accept(), TAcceptFromClient();int (*acceptfn[])() ={ accept, TAcceptFromClient};extern getpeername(), getISOpeername();int (*getpeerfn[])() ={ getpeername, getISOpeername};/* * Note yuckiness here XXX * TReadFromClient takes one more param than read - must fix... */extern int read(), TReadFromClient();int (*readfn[])() = { read, TReadFromClient};extern int write(), TWriteToClient();int (*writefn[])() ={ write, TWriteToClient};extern writev(), TWritevToClient();int (*writevfn[])() ={ writev, TWritevToClient};extern int close(), TDiscFromClient();int (*closefn[])() ={ close, TDiscFromClient};#endif /* ISOCONN */typedef long CCID; /* mask of indices into client socket table */#ifndef X_UNIX_PATH#define X_UNIX_DIR "/tmp/.X11-unix"#define X_UNIX_PATH "/tmp/.X11-unix/X"#endif#ifdef ISOCONNchar *display = NULLCP; /* The display number */#else /* ISOCONN */char *display; /* The display number */#endif /* ISOCONN */int lastfdesc; /* maximum file descriptor */long WellKnownConnections; /* Listener mask */long EnabledDevices; /* mask for input devices that are on */long AllSockets[mskcnt]; /* select on this */long AllClients[mskcnt]; /* available clients */long LastSelectMask[mskcnt]; /* mask returned from last select call */long ClientsWithInput[mskcnt]; /* clients with FULL requests in buffer */long ClientsWriteBlocked[mskcnt];/* clients who cannot receive output */long OutputPending[mskcnt]; /* clients with reply/event data ready to go */long MaxClients = MAXSOCKS ;long OutputBufferSize = BUFSIZ; /* output buffer size (must be > 0) */long NConnBitArrays = mskcnt;long FirstClient;Bool NewOutputPending; /* not yet attempted to write some new output */Bool AnyClientsWriteBlocked; /* true if some client blocked on write */static Bool debug_conns = FALSE;static char whichByteIsFirst;static int SavedAllClients[mskcnt];static int SavedAllSockets[mskcnt];static int SavedClientsWithInput[mskcnt];static Bool GrabDone = FALSE;ClientPtr ConnectionTranslation[MAXSOCKS];extern ClientPtr NextAvailableClient();extern ConnectionInput inputBuffers[];int swappedClients[MAXSOCKS];extern int AutoResetServer();extern int GiveUp();#ifdef UNIXCONNstatic struct sockaddr_un unsock;static int open_unix_socket (){ int oldUmask; int request; unsock.sun_family = AF_UNIX; oldUmask = umask (0);#ifdef X_UNIX_DIR mkdir (X_UNIX_DIR, 0777);#endif strcpy (unsock.sun_path, X_UNIX_PATH); strcat (unsock.sun_path, display); unlink (unsock.sun_path); if ((request = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { Notice ("Creating Unix socket"); } else { if(bind(request,(struct sockaddr *)&unsock, strlen(unsock.sun_path)+2)) Error ("Binding Unix socket"); if (listen (request, 5)) Error ("Unix Listening"); } (void)umask(oldUmask); return request;}#endif /*UNIXCONN *//***************** * CreateWellKnownSockets * At initialization, create the sockets to listen on for new clients. * There are potentially 4: DECnet, UNIX Domain, TCP-IP with MSB first, * with TCP-IP with LSB first. *****************/voidCreateWellKnownSockets(){ int request, i; int whichbyte; /* used to figure out whether this is LSB or MSB */#ifdef TCPCONN struct sockaddr_in insock; int tcpportReg; /* port with same byte order as server */#ifdef SO_LINGER static int linger[2] = { 0, 0 };#endif /* SO_LINGER */#endif /* TCPCONN */#ifdef DNETCONN struct sockaddr_dn dnsock;#endif /* DNETCONN */#ifdef ISOCONN struct TSAPdisconnect tds; struct TSAPdisconnect *td = &tds; struct TSAPaddr tas; struct TSAPaddr *ta = &tas; struct PSAPaddr *pa; AEI aei;#endif /* ISOCONN */ int retry;#ifdef ISOCONN#ifdef ISODEBUG isodetcpath = ISODEPATH;#endif#endif /* ISOCONN */ CLEARBITS(AllSockets); CLEARBITS(AllClients); CLEARBITS(LastSelectMask); CLEARBITS(ClientsWithInput); for (i=0; i<MAXSOCKS; i++) ConnectionTranslation[i] = (ClientPtr)NULL; #ifdef hpux lastfdesc = _NFILE - 1;#else lastfdesc = getdtablesize() - 1;#endif /* hpux */ if (lastfdesc > MAXSOCKS) { lastfdesc = MAXSOCKS; if (debug_conns) ErrorF( "GOT TO END OF SOCKETS %d\n", MAXSOCKS); } WellKnownConnections = 0; whichbyte = 1; if (*(char *) &whichbyte) whichByteIsFirst = 'l'; else whichByteIsFirst = 'B';#ifdef TCPCONN tcpportReg = atoi (display); tcpportReg += X_TCP_PORT; if ((request = socket (AF_INET, SOCK_STREAM, 0)) < 0) { Notice ("Creating TCP socket"); } else { bzero ((char *)&insock, sizeof (insock)); insock.sin_family = AF_INET; insock.sin_port = htons (tcpportReg); insock.sin_addr.s_addr = htonl(INADDR_ANY); retry = 20; while (i = bind(request, (struct sockaddr *) &insock, sizeof (insock))) {#ifdef hpux /* Necesary to restart the server without a reboot */ if (errno == EADDRINUSE) set_socket_option (request, SO_REUSEADDR); if (--retry == 0) Error ("Binding TCP socket"); sleep (1);#else if (--retry == 0) Error ("Binding MSB TCP socket"); sleep (10);#endif /* hpux */ }#ifdef hpux /* return the socket option to the original */ if (errno) unset_socket_option (request, SO_REUSEADDR);#endif /* hpux */#ifdef SO_LINGER if(setsockopt (request, SOL_SOCKET, SO_LINGER, (char *)linger, sizeof(linger))) Notice ("Setting TCP SO_LINGER\n");#endif /* SO_LINGER */ if (listen (request, 5)) Error ("Reg TCP Listening"); WellKnownConnections |= (1 << request); DefineSelf (request);#ifdef ISOCONN fd2family[request] = UNIX_IO;#endif /* ISOCONN */ }#endif /* TCPCONN */#ifdef UNIXCONN if ((request = open_unix_socket ()) != -1) { WellKnownConnections |= (1L << request); unixDomainConnection = request;#ifdef ISOCONN fd2family[request] = UNIX_IO;#endif /* ISOCONN */ }#endif /*UNIXCONN */#ifdef DNETCONN if ((request = socket (AF_DECnet, SOCK_STREAM, 0)) < 0) { Notice ("Creating DECnet socket"); } else { bzero ((char *)&dnsock, sizeof (dnsock)); dnsock.sdn_family = AF_DECnet; sprintf(dnsock.sdn_objname, "X$X%d", atoi (display)); dnsock.sdn_objnamel = strlen(dnsock.sdn_objname); if (bind (request, (struct sockaddr *) &dnsock, sizeof (dnsock))) Error ("Binding DECnet socket"); if (listen (request, 5)) Error ("DECnet Listening"); WellKnownConnections |= (1 << request); DefineSelf (request);#ifdef ISOCONN fd2family[request] = UNIX_IO;#endif /* ISOCONN */ }#endif /* DNETCONN */#ifdef ISOCONN/* * If display is set, its the string after the Colon: * i.e. X0 or X1 or T0 or T1... */ if ((display == NULLCP) || (atoi(display) == 0)) aei = str2aei(TLocalHostName(), DEFAULTTSERVICE); else aei = str2aei(TLocalHostName(), display); if (aei == NULLAEI) { ErrorF("No AEI for me:"); FatalError(TLocalHostName()); }/* * This hack only works if the PSAPaddr and SSAP addrsd are null!! */ if ((pa = aei2addr (aei)) == NULLPA) FatalError("address translation failed"); ta = (struct TSAPaddr *)&(pa->pa_addr.sa_addr);/* * Just put out a listen for now */ if ((request = TNetListen(ta, td)) != OK) { Error(TErrString(td->td_reason)); FatalError("TNetListen"); } WellKnownConnections |= (1 << request); DefineSelf (request); fd2family[request] = ISODE_IO;#endif /* ISOCONN */ if (WellKnownConnections == 0) Error ("No Listeners, nothing to do"); signal (SIGPIPE, SIG_IGN); signal (SIGHUP, AutoResetServer); signal (SIGINT, GiveUp); signal (SIGTERM, GiveUp); FirstClient = request + 1; AllSockets[0] = WellKnownConnections; ResetHosts(display); for (i=0; i<MaxClients; i++) { inputBuffers[i].buffer = (char *) NULL; inputBuffers[i].bufptr = (char *) NULL; inputBuffers[i].bufcnt = 0; inputBuffers[i].lenLastReq = 0; inputBuffers[i].size = 0; }}voidResetWellKnownSockets (){#ifdef UNIXCONN if (unixDomainConnection != -1) { /* * see if the unix domain socket has disappeared */ struct stat statb; if (stat (unsock.sun_path, &statb) == -1 || (statb.st_mode & S_IFMT) != S_IFSOCK) { ErrorF ("Unix domain socket %s trashed, recreating\n", unsock.sun_path); (void) unlink (unsock.sun_path); (void) close (unixDomainConnection); WellKnownConnections &= ~(1L << unixDomainConnection); unixDomainConnection = open_unix_socket (); if (unixDomainConnection != -1) WellKnownConnections |= (1L << unixDomainConnection); } }#endif /* UNIXCONN */}#ifdef ISOCONN/* * Convenience routine... * client = transport descriptor * data, size = buffer * nonblock = NOTOK, blocks, OK, non blocks */TReadFromClient(client, data, size, nonblock)int client, size, nonblock;char *data;{ struct TSAPdisconnect tds; struct TSAPdisconnect *td = &tds; int ret;static struct TSAPdata txs;static struct TSAPdata *tx = &txs; char *aptr; static struct qbuf *qb;static char *qptr;static int ingot, qcpy, result = 0; int q2data;#ifdef ISODEBUG if (isodexbug) { fprintf(stderr, "TReadFromClient %d want %d (%d buffered)\n", client, size, result); }#endif /* ISODEBUG */ if (result == 0) { if ((ret = TReadRequest(client, tx, nonblock, td)) == NOTOK) {#ifdef ISODEBUG if(errno == EWOULDBLOCK ) { fprintf(stderr, "Server TReadReq: would block %s\n", TErrString(td->td_reason)); if (!DR_FATAL(td->td_reason)) errno = EWOULDBLOCK; else errno = EBADF; return ret; } if (isodexbug) fprintf(stderr, "Server TReadReq: %s\n", TErrString(td->td_reason));#endif /* ISODEBUG *//* * map problems here - eg TimeOut... */ if (td->td_reason == DR_TIMER) errno = EWOULDBLOCK; return ret; } result = tx->tx_cc; qb = &(tx->tx_qbuf); qptr = qb->qb_data;#ifdef ISODEBUG if (isodexbug) fprintf(stderr, "TReadRequest want %d got %d\n", size, result);#endif } #ifdef ISODEBUG else { if (isodexbug) fprintf(stderr, "TReadFromClient want %d buffered %d\n", size, result); }#endif/* * Buffer it */ ingot = 0; aptr = data; for(ingot = 0, aptr = data, q2data = min(size, result); ingot<q2data; aptr += qcpy, ingot+= qcpy) { int aleft = q2data - ingot; if (qb->qb_len > aleft) { qcpy = aleft; bcopy(qptr, aptr, qcpy); qptr += aleft; } else { qcpy = qb->qb_len; bcopy(qb->qb_data, aptr, qcpy); if ((qb = qb->qb_forw) == NULL) break; qptr = qb->qb_data; } } if ((result -= ingot) <= 0) { result = 0; TXFREE(tx); } return ingot;}#endif /* ISOCONN *//* We want to read the connection information. If the client doesn't * send us enough data, however, we want to time out eventually. * The scheme is to clear a flag, set an alarm, and keep doing non-blocking * reads until we get all the data we want. If the alarm goes * off, the handler will clear the flag. If we see that the flag is * cleared, we know we've timed out and return with an error. * * there remains one problem with this code: * there is a window of vulnerability in which we might get an alarm * even though all the data has come in properly. This is because I * can't atomically clear the alarm. * * Anyone who sees how to fix this problem should do so and * submit a fix. */jmp_buf env;void TimeOut(){ longjmp(env, 1);}static Bool ReadBuffer(conn, buffer, charsWanted) long conn; char *buffer; int charsWanted;{ char *bptr = buffer; int got, fTimeOut;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -