示例#1
0
文件: io.c 项目: theqvd/vcxsrv
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;
}
示例#2
0
	 */
	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)