int ReadRequestFromClient(ClientPtr client) { OsCommPtr oc = (OsCommPtr) client->osPrivate; ConnectionInputPtr oci = oc->input; int fd = oc->fd; unsigned int gotnow, needed; int result; register xReq *request; Bool need_header; Bool move_header; NextAvailableInput(oc); /* make sure we have an input buffer */ if (!oci) { if ((oci = FreeInputs)) { FreeInputs = oci->next; } else if (!(oci = AllocateInputBuffer())) { YieldControlDeath(); return -1; } oc->input = oci; } #if XTRANS_SEND_FDS /* Discard any unused file descriptors */ while (client->req_fds > 0) { int req_fd = ReadFdFromClient(client); if (req_fd >= 0) close(req_fd); } #endif /* advance to start of next request */ oci->bufptr += oci->lenLastReq; need_header = FALSE; move_header = FALSE; gotnow = oci->bufcnt + oci->buffer - oci->bufptr; if (oci->ignoreBytes > 0) { if (oci->ignoreBytes > oci->size) needed = oci->size; else needed = oci->ignoreBytes; } else if (gotnow < sizeof(xReq)) { /* We don't have an entire xReq yet. Can't tell how big * the request will be until we get the whole xReq. */ needed = sizeof(xReq); need_header = TRUE; } else { /* We have a whole xReq. We can tell how big the whole * request will be unless it is a Big Request. */ request = (xReq *) oci->bufptr; needed = get_req_len(request, client); if (!needed && client->big_requests) { /* It's a Big Request. */ move_header = TRUE; if (gotnow < sizeof(xBigReq)) { /* Still need more data to tell just how big. */ needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */ need_header = TRUE; } else needed = get_big_req_len(request, client); } client->req_len = needed; needed <<= 2; /* needed is in bytes now */ } if (gotnow < needed) { /* Need to read more data, either so that we can get a * complete xReq (if need_header is TRUE), a complete * xBigReq (if move_header is TRUE), or the rest of the * request (if need_header and move_header are both FALSE). */ oci->lenLastReq = 0; if (needed > maxBigRequestSize << 2) { /* request is too big for us to handle */ /* * Mark the rest of it as needing to be ignored, and then return * the full size. Dispatch() will turn it into a BadLength error. */ oci->ignoreBytes = needed - gotnow; oci->lenLastReq = gotnow; return needed; } if ((gotnow == 0) || ((oci->bufptr - oci->buffer + needed) > oci->size)) { /* no data, or the request is too big to fit in the buffer */ if ((gotnow > 0) && (oci->bufptr != oci->buffer)) /* save the data we've already read */ memmove(oci->buffer, oci->bufptr, gotnow); if (needed > oci->size) { /* make buffer bigger to accomodate request */ char *ibuf; ibuf = (char *) realloc(oci->buffer, needed); if (!ibuf) { YieldControlDeath(); return -1; } oci->size = needed; oci->buffer = ibuf; } oci->bufptr = oci->buffer; oci->bufcnt = gotnow; } /* XXX this is a workaround. This function is sometimes called * after the trans_conn has been freed. In this case trans_conn * will be null. Really ought to restructure things so that we * never get here in those circumstances. */ if (!oc->trans_conn) { /* treat as if an error occured on the read, which is what * used to happen */ YieldControlDeath(); return -1; } result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt, oci->size - oci->bufcnt); if (result <= 0) { if ((result < 0) && ETEST(errno)) { #if defined(SVR4) && defined(__i386__) && !defined(sun) if (0) #endif { YieldControlNoInput(fd); return 0; } } YieldControlDeath(); return -1; } oci->bufcnt += result; gotnow += result; /* free up some space after huge requests */ if ((oci->size > BUFWATERMARK) && (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) { char *ibuf; ibuf = (char *) realloc(oci->buffer, BUFSIZE); if (ibuf) { oci->size = BUFSIZE; oci->buffer = ibuf; oci->bufptr = ibuf + oci->bufcnt - gotnow; } } if (need_header && gotnow >= needed) { /* We wanted an xReq, now we've gotten it. */ request = (xReq *) oci->bufptr; needed = get_req_len(request, client); if (!needed && client->big_requests) { move_header = TRUE; if (gotnow < sizeof(xBigReq)) needed = bytes_to_int32(sizeof(xBigReq)); else needed = get_big_req_len(request, client); } client->req_len = needed; needed <<= 2; } if (gotnow < needed) { /* Still don't have enough; punt. */ YieldControlNoInput(fd); return 0; } } if (needed == 0) { if (client->big_requests) needed = sizeof(xBigReq); else needed = sizeof(xReq); } /* If there are bytes to ignore, ignore them now. */ if (oci->ignoreBytes > 0) { assert(needed == oci->ignoreBytes || needed == oci->size); /* * The _XSERVTransRead call above may return more or fewer bytes than we * want to ignore. Ignore the smaller of the two sizes. */ if (gotnow < needed) { oci->ignoreBytes -= gotnow; oci->bufptr += gotnow; gotnow = 0; } else { oci->ignoreBytes -= needed; oci->bufptr += needed; gotnow -= needed; } needed = 0; } oci->lenLastReq = needed; /* * Check to see if client has at least one whole request in the * buffer beyond the request we're returning to the caller. * If there is only a partial request, treat like buffer * is empty so that select() will be called again and other clients * can get into the queue. */ gotnow -= needed; if (gotnow >= sizeof(xReq)) { request = (xReq *) (oci->bufptr + needed); if (gotnow >= (result = (get_req_len(request, client) << 2)) && (result || (client->big_requests && (gotnow >= sizeof(xBigReq) && gotnow >= (get_big_req_len(request, client) << 2)))) ) FD_SET(fd, &ClientsWithInput); else { if (!SmartScheduleDisable) FD_CLR(fd, &ClientsWithInput); else YieldControlNoInput(fd); } } else { if (!gotnow) AvailableInput = oc; if (!SmartScheduleDisable) FD_CLR(fd, &ClientsWithInput); else YieldControlNoInput(fd); } if (SmartScheduleDisable) if (++timesThisConnection >= MAX_TIMES_PER) YieldControl(); if (move_header) { request = (xReq *) oci->bufptr; oci->bufptr += (sizeof(xBigReq) - sizeof(xReq)); *(xReq *) oci->bufptr = *request; oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq)); client->req_len -= bytes_to_int32(sizeof(xBigReq) - sizeof(xReq)); } client->requestBuffer = (void *) oci->bufptr; #ifdef DEBUG_COMMUNICATION { xReq *req = client->requestBuffer; ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n", client->index, req->reqType, req->data, req->length); } #endif return needed; }
*/ request = (xReq *)oci->bufptr; needed = get_req_len(request, client); #ifdef BIGREQS if (!needed && client->big_requests) { /* It's a Big Request. */ move_header = TRUE; if (gotnow < sizeof(xBigReq)) { /* Still need more data to tell just how big. */ needed = sizeof(xBigReq) >> 2; /* needed is in CARD32s now */ need_header = TRUE; } else needed = get_big_req_len(request, client); } #endif client->req_len = needed; needed <<= 2; /* needed is in bytes now */ } if (gotnow < needed) { /* Need to read more data, either so that we can get a * complete xReq (if need_header is TRUE), a complete * xBigReq (if move_header is TRUE), or the rest of the * request (if need_header and move_header are both FALSE). */ oci->lenLastReq = 0; if (needed > MAXBUFSIZE)