Hands-on Projects for the Linux Graphics Subsystem
|
EstablishNewConnections(), called from WaitForSomething() via QueueWorkProc(), in the Dispatch() loop is the X Server mechanism to accept new X Clients. It also updates the AllClients and AllSockets fd sets used by select().
For QueueWorkProc we read at the Definition of the Porting Layer for the X v11 Sample Server:
5.9. Work Queue To queue work for execution when all clients are in a stable state (i.e. just before calling select() in WaitForSome- thing), call: Bool QueueWorkProc(function,client,closure) Bool (*function)(); ClientPtr client; pointer closure; When the server is about to suspend itself, the given func- tion will be executed: (*function) (client, closure) Neither client nor closure are actually used inside the work queue routines. |
A simplified WaitForSomething() while loop with the QueueWorkProc() and ProcessWorkQueue(), that processes the work queue is shown bellow. For more details on WaitForSomething() see section 3.2.5.2.
while (1) { if (workQueue) ProcessWorkQueue(); . . . i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); . . . XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); if (XFD_ANYSET(&tmp_set)) QueueWorkProc(EstablishNewConnections, NULL, (pointer)&LastSelectMask); . . . } |
EstablishNewConnections() has the prototype:
Bool EstablishNewConnections(ClientPtr clientUnused, pointer closure)
XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections); XFD_COPYSET(&tmask, &readyconnections); if (!XFD_ANYSET(&readyconnections)) return TRUE; |
the closure is substituted by the LastSelectMask argument. As seen also in section 3.2.5.2 WellKnownConnections is defined in connection.c as the fd set of the client connections with the X Server so far. LastSelectMask is filtered with the 'known connections' since LastSelectMask include other fds as well e.g. of device connections. Then it is copied to readyconnections.
The following part closes X Clients that timeout. TimeOutValue is defined in globals.c as:
CARD32 TimeOutValue = DEFAULT_TIMEOUT * MILLI_PER_SECOND;
Where DEFAULT_TIMEOUT is defined to site.h as:
#define DEFAULT_TIMEOUT 60 /* seconds */and MILLI_PER_SECOND is defined in misc.h as:
#define MILLI_PER_SECOND (1000)
connect_time = GetTimeInMillis(); /* kill off stragglers */ for (i=1; i<currentMaxClients; i++) { if ((client = clients[i])) { oc = (OsCommPtr)(client->osPrivate); if ((oc && (oc->conn_time != 0) && (connect_time - oc->conn_time) >= TimeOutValue) || (client->noClientException != Success && !client->clientGone)) CloseDownClient(client); } } |
for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) { while (readyconnections.fds_bits[i]) { XtransConnInfo trans_conn, new_trans_conn; int status; curconn = ffs (readyconnections.fds_bits[i]) - 1; readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); curconn += (i * (sizeof(fd_mask)*8)) if ((trans_conn = lookup_trans_conn (curconn)) == NULL) continue; if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) continue; newconn = _XSERVTransGetConnectionNumber (new_trans_conn); if (newconn < lastfdesc) { int clientid; clientid = ConnectionTranslation[newconn]; if(clientid && (client = clients[clientid])) CloseDownClient(client); } _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); if (!AllocNewConnection (new_trans_conn, newconn, connect_time )) { ErrorConnMax(new_trans_conn); _XSERVTransClose(new_trans_conn); } } } return TRUE; |
fd_set is defined in the header file sys/select.h included via the X11/Xos.h header file as:
typedef struct fd_set { fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; } fd_set; |
for a description on fd_set see Waiting for I/O.
fd_mask is defined in select.h as long and howmany as:
#define howmany(x, y) (((x)+((y)-1))/(y))
XFD_SETSIZE is defined as:
#define XFD_SETSIZE 256
and NFDBITS as:
#define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */
where NBBY is 8.
Also for the ffs() (find first bit) read the ffs man page.
We examine next more detailed the parts of the previous green code box:
for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) { while (readyconnections.fds_bits[i]) |
the for loop increases i from 0 to the max number of long (4-bytes) integer dedicated for file descriptors. This is returned by howmany.
The while loop then searches in each of those long integers for bits that are set (longs have a non zero value).
curconn = ffs (readyconnections.fds_bits[i]) - 1; |
ffs() is used to extract the position of the first bit set and this is returned as curconn (current connection). This is the fd of listener that's ready.
readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); curconn += (i * (sizeof(fd_mask)*8)) |
The specific fd is cleared from readyconnections and the curconn from relative value (bit inside a long) takes an absolute value (bit inside all longs that make up fds_bits[]).
if ((trans_conn = lookup_trans_conn (curconn)) == NULL) continue; |
lookup_trans_conn() is used, which returns for a given fd to trans_conn the XtransConnInfo info connection struct:
static XtransConnInfo lookup_trans_conn (int fd) { if (ListenTransFds) { int i; for (i = 0; i < ListenTransCount; i++) if (ListenTransFds[i] == fd) return ListenTransConns[i]; } return (NULL); } |
ListenTransFds[], ListenTransConns[] are filled in CreateWellKnownSockets() via _XSERVTransMakeAllCOTSServerListeners() or TRANS(MakeAllCOTSServerListeners) (see section 3.2.1).
We return back to EstablishNewConnections() code:
if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) continue; |
trans_conn is passed then to _XSERVTransAccept(), which is implemented as TRANS(Accept), since the latter according to Xtrans.h is resolved to _XSERVTransAccept():
#ifdef XSERV_t #if !defined(UNIXCPP) || defined(ANSICPP) #define TRANS(func) _XSERVTrans##func |
The implementation of of TRANS(Accept) is found at Xtrans.c:
XtransConnInfo TRANS(Accept) (XtransConnInfo ciptr, int *status) { XtransConnInfo newciptr; PRMSG (2,"Accept(%d)\n", ciptr->fd, 0, 0); newciptr = ciptr->transptr->Accept (ciptr, status); if (newciptr) newciptr->transptr = ciptr->transptr; return newciptr; } |
trans_conn (the argument of type XtransConnInfo that substitutes the ciptr parameter) provides the specific 'Accept' routine. If as case example considers that the Xtransport, transptr points to, is the TRANS(SocketTCPFuncs) - see section 1.4.2 - then Accept becomes TRANS(SocketINETAccept), which is actually resolved to a socket API's accept() call. As a result a new XtransConnInfo is returned for the new connection as new_trans_conn.
newconn = _XSERVTransGetConnectionNumber (new_trans_conn); |
From XtransConnInfo the fd of the new connection (newconn), which is usually of interest in the sockets API is extracted with _XSERVTransGetConnectionNumber, implemented as TRANS(GetConnectionNumber):
int TRANS(GetConnectionNumber) (XtransConnInfo ciptr) { return ciptr->fd; } |
The TRANS_NONBLOCKING option is set for the new connection:
_XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); |
_XSERVTransSetOption() is implemented as TRANS(SetOption), which for TRANS_NONBLOCKING with the third argument 1 sets the well known socket API's O_NONBLOCK flag.
if (!AllocNewConnection (new_trans_conn, newconn, connect_time )) { ErrorConnMax(new_trans_conn); _XSERVTransClose(new_trans_conn); } |
AllocNewConnection() is implemented as:
static ClientPtr #ifdef LBX AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time, int (*Flush)( ClientPtr /*who*/, OsCommPtr /*oc*/, char * /*extraBuf*/, int /*extraCount*/), void (*Close)( ClientPtr /*client*/), LbxProxyPtr proxy) #else AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) #endif { OsCommPtr oc; ClientPtr client; if ( #ifdef LBX trans_conn && #endif #ifndef WIN32 fd >= lastfdesc #else XFD_SETCOUNT(&AllClients) >= MaxClients #endif ) return NullClient; oc = (OsCommPtr)xalloc(sizeof(OsCommRec)); if (!oc) return NullClient; oc->trans_conn = trans_conn; oc->fd = fd; oc->input = (ConnectionInputPtr)NULL; oc->output = (ConnectionOutputPtr)NULL; oc->auth_id = None; oc->conn_time = conn_time; #ifdef LBX oc->proxy = proxy; oc->Flush = Flush; oc->Close = Close; oc->largereq = (ConnectionInputPtr) NULL; #endif if (!(client = NextAvailableClient((pointer)oc))) { xfree (oc); return NullClient; } #ifdef LBX if (trans_conn) #endif { #if !defined(WIN32) ConnectionTranslation[fd] = client->index; #else SetConnectionTranslation(fd, client->index); #endif if (GrabInProgress) { FD_SET(fd, &SavedAllClients); FD_SET(fd, &SavedAllSockets); } else { FD_SET(fd, &AllClients); FD_SET(fd, &AllSockets); } } |
In the case fd >= lastfdesc, where lastfdesc is the maximum file descriptor no more clients are accepted and the NullClient is returned. This is defined in dix.h as:
#define NullClient ((ClientPtr) 0)
oc a OsCommPtr is allocated from the heap via xalloc. Some of its fields like trans_conn and fd are filled then. As we saw in section 3.2.5.3 OsCommPtr is defined in osdep.h as:
typedef struct _osComm { int fd; ConnectionInputPtr input; ConnectionOutputPtr output; XID auth_id; /* authorization id */ #ifdef K5AUTH k5_state authstate; /* state of setup auth conversation */ #endif CARD32 conn_time; /* timestamp if not established, else 0 */ struct _XtransConnInfo *trans_conn; /* transport connection object */ #ifdef LBX OsProxyPtr proxy; ConnectionInputPtr largereq; OsCloseFunc Close; OsFlushFunc Flush; #endif } OsCommRec, *OsCommPtr; |
oc is the argument for NextAvailableClient() that is called next.
This function is implemented as:
/************************ * int NextAvailableClient(ospriv) * * OS dependent portion can't assign client id's because of CloseDownModes. * Returns NULL if there are no free clients. *************************/ ClientPtr NextAvailableClient(pointer ospriv) { register int i; register ClientPtr client; xReq data; i = nextFreeClientID; if (i == MAXCLIENTS) return (ClientPtr)NULL; clients[i] = client = (ClientPtr)xalloc(totalClientSize); if (!client) return (ClientPtr)NULL; InitClient(client, i, ospriv); InitClientPrivates(client); if (!InitClientResources(client)) { xfree(client); return (ClientPtr)NULL; } data.reqType = 1; data.length = (sz_xReq + sz_xConnClientPrefix) >> 2; if (!InsertFakeRequest(client, (char *)&data, sz_xReq)) { FreeClientResources(client); xfree(client); return (ClientPtr)NULL; } if (i == currentMaxClients) currentMaxClients++; while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID]) nextFreeClientID++; if (ClientStateCallback) { NewClientInfoRec clientinfo; clientinfo.client = client; clientinfo.prefix = (xConnSetupPrefix *)NULL; clientinfo.setup = (xConnSetup *) NULL; CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); } return(client); } |
NextAvailableClient() allocates a new client from the heap via xalloc() and places it in the next available entry in clients[]. It then initializes the client by calling InitClient(), implemented as:
void InitClient(ClientPtr client, int i, pointer ospriv) { client->index = i; client->sequence = 0; client->clientAsMask = ((Mask)i) << CLIENTOFFSET; client->clientGone = FALSE; if (i) { client->closeDownMode = DestroyAll; client->lastDrawable = (DrawablePtr)WindowTable[0]; client->lastDrawableID = WindowTable[0]->drawable.id; } else { client->closeDownMode = RetainPermanent; client->lastDrawable = (DrawablePtr)NULL; client->lastDrawableID = INVALID; } client->lastGC = (GCPtr) NULL; client->lastGCID = INVALID; client->numSaved = 0; client->saveSet = (SaveSetElt *)NULL; client->noClientException = Success; #ifdef DEBUG client->requestLogIndex = 0; #endif client->requestVector = InitialVector; client->osPrivate = ospriv; client->swapped = FALSE; client->big_requests = FALSE; client->priority = 0; client->clientState = ClientStateInitial; #ifdef XKB if (!noXkbExtension) { client->xkbClientFlags = 0; client->mapNotifyMask = 0; QueryMinMaxKeyCodes(&client->minKC,&client->maxKC); } #endif client->replyBytesRemaining = 0; #ifdef LBX client->readRequest = StandardReadRequestFromClient; #endif #ifdef XCSECURITY client->trustLevel = XSecurityClientTrusted; client->CheckAccess = NULL; client->authId = 0; #endif #ifdef XAPPGROUP client->appgroup = NULL; #endif client->fontResFunc = NULL; #ifdef SMART_SCHEDULE client->smart_priority = 0; client->smart_start_tick = SmartScheduleTime; client->smart_stop_tick = SmartScheduleTime; client->smart_check_tick = SmartScheduleTime; #endif } |
At this point the request vector of the client (the array of the X Protocol routines that execute according to the reqType the client sends) is set to InitialVector, so that it has the chance to change latter to ProcVector[] or SwappedProcVector[].
client->requestVector = InitialVector; |
InitialVector is found in tables.c as:
int (* InitialVector[3]) ( ClientPtr /* client */ ) = { 0, ProcInitialConnection, ProcEstablishConnection }; |
NextAvailableClient() calls also InitClientPrivates() to initialize devPrivates. For devPrivates we read from Definition of the Porting Layer for the X v11 Sample Server:
devPrivates are arrays of values attached to various data structures (Screens, GCs, Windows, and Pixmaps currently). These arrays are sized dynamically at server startup (and reset) time as various modules allocate portions of them. They can be used for any purpose; each array entry is actually a union, DevUnion, of common useful types (pointer, long and unsigned long). |
NextAvailableClient() executes then the following important lines of code:
data.reqType = 1; data.length = (sz_xReq + sz_xConnClientPrefix) >> 2; if (!InsertFakeRequest(client, (char *)&data, sz_xReq)) |
InsertFakeRequest() places a fake request (that is a request the client never issued) on the client's buffer (As we see bellow the initial message to the X server doe not include a reqType and the X Server prepares one on behalf of the client). This function is implemented as:
Bool InsertFakeRequest(ClientPtr client, char *data, int count) { OsCommPtr oc = (OsCommPtr)client->osPrivate; ConnectionInputPtr oci = oc->input; int fd = oc->fd; int gotnow, moveup; if (AvailableInput) { if (AvailableInput != oc) { ConnectionInputPtr aci = AvailableInput->input; if (aci->size > BUFWATERMARK) { xfree(aci->buffer); xfree(aci); } else { aci->next = FreeInputs; FreeInputs = aci; } AvailableInput->input = (ConnectionInputPtr)NULL; } AvailableInput = (OsCommPtr)NULL; } if (!oci) { if ((oci = FreeInputs)) FreeInputs = oci->next; else if (!(oci = AllocateInputBuffer())) return FALSE; oc->input = oci; } oci->bufptr += oci->lenLastReq; oci->lenLastReq = 0; gotnow = oci->bufcnt + oci->buffer - oci->bufptr; if ((gotnow + count) > oci->size) { char *ibuf; ibuf = (char *)xrealloc(oci->buffer, gotnow + count); if (!ibuf) return(FALSE); oci->size = gotnow + count; oci->buffer = ibuf; oci->bufptr = ibuf + oci->bufcnt - gotnow; } moveup = count - (oci->bufptr - oci->buffer); if (moveup > 0) { if (gotnow > 0) memmove(oci->bufptr + moveup, oci->bufptr, gotnow); oci->bufptr += moveup; oci->bufcnt += moveup; } memmove(oci->bufptr - count, data, count); oci->bufptr -= count; gotnow += count; if ((gotnow >= sizeof(xReq)) && (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2))) FD_SET(fd, &ClientsWithInput); else YieldControlNoInput(); return(TRUE); } |
In our case the request type is 1 and the request vector is InitialVector[]. The routine we find at index 1 in InitialVector[] is ProcInitialConnection().
int ProcInitialConnection(register ClientPtr client) { REQUEST(xReq); register xConnClientPrefix *prefix; int whichbyte = 1; prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq); if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B')) return (client->noClientException = -1); if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) || (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l'))) { client->swapped = TRUE; SwapConnClientPrefix(prefix); } stuff->reqType = 2; stuff->length += ((prefix->nbytesAuthProto + (unsigned)3) >> 2) + ((prefix->nbytesAuthString + (unsigned)3) >> 2); if (client->swapped) { swaps(&stuff->length, whichbyte); } ResetCurrentRequest(client); return (client->noClientException); } |
ProcInitialConnection() is executed with the following instruction of the Dispatch() loop (see section 3.2.5):
result = (* client->requestVector[MAJOROP])(client);This is described more detailed in section 3.2.5.3.
As we mentioned in section 1.2 the initial message the X client sends to the X server has the format:
typedef struct { CARD8 byteOrder; BYTE pad; CARD16 majorVersion B16, minorVersion B16; CARD16 nbytesAuthProto B16; /* Authorization protocol */ CARD16 nbytesAuthString B16; /* Authorization string */ CARD16 pad2 B16; } xConnClientPrefix; |
The byteOrder field is examined. This indicates the byte order. It was either filled by the X client as 'B' (Most Significant Byte - MSB first) or 'l' (Less Significant Byte - LSB first). ASCII upper case B is the octal 102 and ASCII lower case l is the octal 154 (see the ascii table). The code that does that in the X client side is found at OpenDis.c:
endian = 1; if (*(char *) &endian) client.byteOrder = '\154'; /* 'l' */ else client.byteOrder = '\102'; /* 'B' */ |
endian is declared in this file as int (32 bits). Variable "endian" is an integer variable, thus a 32-bit variable (on most systems) and by doing "&endian" it converts the variable from "int" to "int*" and therefore &endian describes the location of the number in memory. By doing:
(char *) &endianIt tells that from the 4 bytes in memory used for the variable "endian", only use the first one. (It casts the variable as a char*, instead of int*. int = 4bytes; char = 1 byte). And finally when doing:
*(char*)&endianIt tells to read the content of that byte in memory. If it is set to "1" we're on a little endian machine. This should be the memory content in both systems:
Little endian: 00 00 00 01 Big endian: 01 00 00 00So, by reading the first byte we can tell if it is little- of big-endian.
The X Server checks the endianess with the following code of ProcInitialConnection():
if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) || (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l'))) { client->swapped = TRUE;where whichbyte is defined as:
int whichbyte = 1;
whichbyte for the X Server (the current process) can either be:
00 00 00 01 (Little endian X Server) or 01 00 00 00 (Big endian X Server)
In the Little endian X Server case (*(char *) &whichbyte) is 01
and (!(*(char *) &whichbyte) is 00.
In the Big endian X Server case (*(char *) &whichbyte) is 00
and (!(*(char *) &whichbyte) is 01.
We try to detected the swapped case, where X Server and X client looks opsite at the byte order. Let's say that the X Server is Little endian. In that case from the previous 'if' condition ((*(char *) &whichbyte) is TRUE and (in the oposite case that X client is Big endian (prefix->byteOrder == 'B') also holds TRUE and the result is TRUE. A case that requires swapping in the client bytes is therefore detected and SwapConnClientPrefix() is used to put the bytes in order of the client prefix (the initial message).
We continue with the following part of ProcInitialConnection() code:
stuff->reqType = 2; stuff->length += ((prefix->nbytesAuthProto + (unsigned)3) >> 2) + ((prefix->nbytesAuthString + (unsigned)3) >> 2);
reqType becomes 2, which is the index in InitialVector[] for the ProcEstablishConnection() routine.
int ProcEstablishConnection(register ClientPtr client) { char *reason, *auth_proto, *auth_string; register xConnClientPrefix *prefix; REQUEST(xReq); prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq); auth_proto = (char *)prefix + sz_xConnClientPrefix; auth_string = auth_proto + ((prefix->nbytesAuthProto + 3) & ~3); if ((prefix->majorVersion != X_PROTOCOL) || (prefix->minorVersion != X_PROTOCOL_REVISION)) reason = "Protocol version mismatch"; else reason = ClientAuthorized(client, (unsigned short)prefix->nbytesAuthProto, auth_proto, (unsigned short)prefix->nbytesAuthString, auth_string); /* * If Kerberos is being used for this client, the clientState * will be set to ClientStateAuthenticating at this point. * More messages need to be exchanged among the X server, Kerberos * server, and client to figure out if everyone is authorized. * So we don't want to send the connection setup info yet, since * the auth step isn't really done. */ if (client->clientState == ClientStateCheckingSecurity) client->clientState = ClientStateCheckedSecurity; else if (client->clientState != ClientStateAuthenticating) return(SendConnSetup(client, reason)); return(client->noClientException); } |
The following instruction, which is called from ProcInitialConnection():
ResetCurrentRequest(client);causes ProcEstablishConnection() to be executed replacing ProcInitialConnection() as the current fake request. Again with the following instruction of the Dispatch() loop (see section 3.2.5):
result = (* client->requestVector[MAJOROP])(client);
ResetCurrentRequest() is implemented as:
void ResetCurrentRequest(ClientPtr client) { OsCommPtr oc = (OsCommPtr)client->osPrivate; register ConnectionInputPtr oci = oc->input; int fd = oc->fd; register xReq *request; int gotnow, needed; #ifdef LBX LbxClientPtr lbxClient = LbxClient(client); if (lbxClient) { LbxSetForBlock(lbxClient); if (!oci) { AppendFakeRequest(client, client->requestBuffer, client->req_len << 2); return; } } #endif if (AvailableInput == oc) AvailableInput = (OsCommPtr)NULL; oci->lenLastReq = 0; gotnow = oci->bufcnt + oci->buffer - oci->bufptr; if (gotnow < sizeof(xReq)) { YieldControlNoInput(); } else { request = (xReq *)oci->bufptr; needed = get_req_len(request, client); #ifdef BIGREQS if (!needed && client->big_requests) { oci->bufptr -= sizeof(xBigReq) - sizeof(xReq); *(xReq *)oci->bufptr = *request; ((xBigReq *)oci->bufptr)->length = client->req_len; if (client->swapped) { char n; swapl(&((xBigReq *)oci->bufptr)->length, n); } } #endif if (gotnow >= (needed << 2)) { if (FD_ISSET(fd, &AllClients)) { FD_SET(fd, &ClientsWithInput); } else { FD_SET(fd, &IgnoredClientsWithInput); } YieldControl(); } else YieldControlNoInput(); } } |
Two are the important parts of ProcEstablishConnection():
I. The client authorization via ClientAuthorized():
/***************************************************************** * ClientAuthorized * * Sent by the client at connection setup: * typedef struct _xConnClientPrefix { * CARD8 byteOrder; * BYTE pad; * CARD16 majorVersion, minorVersion; * CARD16 nbytesAuthProto; * CARD16 nbytesAuthString; * } xConnClientPrefix; * * It is hoped that eventually one protocol will be agreed upon. In the * mean time, a server that implements a different protocol than the * client expects, or a server that only implements the host-based * mechanism, will simply ignore this information. * *****************************************************************/ char * ClientAuthorized(ClientPtr client, unsigned int proto_n, char *auth_proto, unsigned int string_n, char *auth_string) { OsCommPtr priv; Xtransaddr *from = NULL; int family; int fromlen; XID auth_id; char *reason = NULL; XtransConnInfo trans_conn; int restore_trans_conn = 0; ClientPtr lbxpc = NULL; priv = (OsCommPtr)client->osPrivate; trans_conn = priv->trans_conn; #ifdef LBX if (!trans_conn) { /* * Since trans_conn is NULL, this must be a proxy's client for * which we have NO address. Therefore, we will temporarily * set the client's trans_conn to the proxy's trans_conn and * after CheckAuthorization the client's trans_conn will be * restored. * * If XDM-AUTHORIZATION-1 is being used, CheckAuthorization * will eventually call XdmAuthorizationValidate and this * later function may use the client's trans_conn to get the * client's address. Since a XDM-AUTH-1 auth string includes * the client's address, this address is compared to the address * in the client's trans_conn. If the proxy and client are * on the same host, the comparison will fail; otherwise the * comparison will fail and the client will not be authorized * to connect to the server. * * The basis for this additional code is to prevent a * NULL pointer dereference of the client's trans_conn. * The fundamental problem - the fact that the client's * trans_conn is NULL - is because the NewClient * request in version 1.0 of the LBX protocol does not * send the client's address to the server. When the * spec is changed and the client's address is sent to * server in the NewClient request, this additional code * should be removed. * * See defect number XWSog08218 for more information. */ lbxpc = LbxProxyClient(priv->proxy); trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn; priv->trans_conn = trans_conn; restore_trans_conn = 1; } #endif auth_id = CheckAuthorization (proto_n, auth_proto, string_n, auth_string, client, &reason); #ifdef LBX if (! priv->trans_conn) { if (auth_id == (XID) ~0L && !GetAccessControl()) auth_id = ((OsCommPtr)lbxpc->osPrivate)->auth_id; #ifdef XCSECURITY else if (auth_id != (XID) ~0L && !SecuritySameLevel(lbxpc, auth_id)) { auth_id = (XID) ~0L; reason = "Client trust level differs from that of LBX Proxy"; } #endif } #endif if (auth_id == (XID) ~0L) { if ( #ifdef XCSECURITY (proto_n == 0 || strncmp (auth_proto, XSecurityAuthorizationName, proto_n) != 0) && #endif _XSERVTransGetPeerAddr (trans_conn, &family, &fromlen, &from) != -1) { if ( #ifdef LBX !trans_conn || #endif InvalidHost ((struct sockaddr *) from, fromlen, client)) AuthAudit(client, FALSE, (struct sockaddr *) from, fromlen, proto_n, auth_proto, auth_id); else { auth_id = (XID) 0; if (auditTrailLevel > 1) AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen, proto_n, auth_proto, auth_id); } xfree ((char *) from); } if (auth_id == (XID) ~0L) { #ifdef LBX /* * Restore client's trans_conn state */ if (restore_trans_conn) { priv->trans_conn = NULL; } #endif if (reason) return reason; else return "Client is not authorized to connect to Server"; } } else if (auditTrailLevel > 1) { if (_XSERVTransGetPeerAddr (trans_conn, &family, &fromlen, &from) != -1) { AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen, proto_n, auth_proto, auth_id); xfree ((char *) from); } } priv->auth_id = auth_id; priv->conn_time = 0; #ifdef XDMCP /* indicate to Xdmcp protocol that we've opened new client */ XdmcpOpenDisplay(priv->fd); #endif /* XDMCP */ #ifdef XAPPGROUP if (ClientStateCallback) XagCallClientStateChange (client); #endif /* At this point, if the client is authorized to change the access control * list, we should getpeername() information, and add the client to * the selfhosts list. It's not really the host machine, but the * true purpose of the selfhosts list is to see who may change the * access control list. */ #ifdef LBX if (restore_trans_conn) { priv->trans_conn = NULL; } #endif return((char *)NULL); } |
For the Kerberos Authentication see Kerberos Authentication of X Connections.
II. The execution of the following instruction:
return(SendConnSetup(client, reason));
SendConnSetup() is implemented as:
int SendConnSetup(register ClientPtr client, char *reason) { register xWindowRoot *root; register int i; int numScreens; char* lConnectionInfo; xConnSetupPrefix* lconnSetupPrefix; if (reason) { xConnSetupPrefix csp; csp.success = xFalse; csp.lengthReason = strlen(reason); csp.length = (csp.lengthReason + (unsigned)3) >> 2; csp.majorVersion = X_PROTOCOL; csp.minorVersion = X_PROTOCOL_REVISION; if (client->swapped) WriteSConnSetupPrefix(client, &csp); else (void)WriteToClient(client, sz_xConnSetupPrefix, (char *) &csp); (void)WriteToClient(client, (int)csp.lengthReason, reason); return (client->noClientException = -1); } numScreens = screenInfo.numScreens; lConnectionInfo = ConnectionInfo; lconnSetupPrefix = &connSetupPrefix; /* We're about to start speaking X protocol back to the client by * sending the connection setup info. This means the authorization * step is complete, and we can count the client as an * authorized one. */ nClients++; client->requestVector = client->swapped ? SwappedProcVector : ProcVector; client->sequence = 0; #ifdef XAPPGROUP XagConnectionInfo (client, &lconnSetupPrefix, &lConnectionInfo, &numScreens); #endif ((xConnSetup *)lConnectionInfo)->ridBase = client->clientAsMask; ((xConnSetup *)lConnectionInfo)->ridMask = RESOURCE_ID_MASK; #ifdef MATCH_CLIENT_ENDIAN ((xConnSetup *)lConnectionInfo)->imageByteOrder = ClientOrder (client); ((xConnSetup *)lConnectionInfo)->bitmapBitOrder = ClientOrder (client); #endif /* fill in the "currentInputMask" */ root = (xWindowRoot *)(lConnectionInfo + connBlockScreenStart); #ifdef PANORAMIX if (noPanoramiXExtension) numScreens = screenInfo.numScreens; else numScreens = ((xConnSetup *)ConnectionInfo)->numRoots; #endif for (i=0; i |
SendConnSetup() updates the client's requestvector, which is the table with the opcodes that correspond to a client's request to either SwappedProcVector or ProcVector:
client->requestVector = client->swapped ? SwappedProcVector : ProcVector; |
Both tables ProcVector, which provides the functions that server the client request using as index the reqType for client messages that need not swapping in their byte order the and SwappedProcVector which is the table for swapped clients are found in tables.c.
Also SendConnSetup() uses WriteToClient() to send a reply of the form xConnSetupPrefix and establish the connection.
typedef struct { CARD8 success; BYTE lengthReason; /*num bytes in string following if failure */ CARD16 majorVersion B16, minorVersion B16; CARD16 length B16; /* 1/4 additional bytes in setup info */ } xConnSetupPrefix; |
REFERENCES: