int
FlushClient(
    ClientPtr   client,
    OsCommPtr   oc,
    char       *extraBuf,
    int         extraCount,
    int         padsize)
{
    ConnectionOutputPtr oco = oc->output;
    int         fd = oc->fd;
    struct iovec iov[3];
    char        padBuffer[3];
    long        written;
    long        notWritten;
    long        todo;

    if (!oco)
	return 0;
    written = 0;
    notWritten = oco->count + extraCount + padsize;
    todo = notWritten;
    while (notWritten) {
	long        before = written;
	long        remain = todo;
	int         i = 0;
	long        len;

	/*-
	 * You could be very general here and have "in" and "out" iovecs and
	 * write a loop without using a macro, but what the heck.  This
	 * translates to:
	 *
	 * 	how much of this piece is new?
	 *	if more new then we are trying this time, clamp
	 *	if nothing new
	 *	    then bump down amount already written, for next piece
	 *	    else put new stuff in iovec, will need all of next piece
	 *
	 * Note that todo had better be at least 1 or else we'll end up
	 * writing 0 iovecs.
	 */

#define	InsertIOV(pointer, length)	\
	len = (length) - before;	\
	if (len > remain)		\
	    len = remain;		\
	if (len <= 0) {			\
	    before = (-len);		\
	} else {			\
	    iov[i].iov_len = len;	\
	    iov[i].iov_base = (pointer) + before; \
	    i++;			\
	    remain -= len;		\
	    before = 0;			\
	}

	InsertIOV((char *) oco->buf, oco->count);
	InsertIOV(extraBuf, extraCount);
	InsertIOV(padBuffer, padsize);

	errno = 0;
	if (oc->trans_conn && (len = _FontTransWritev(oc->trans_conn, iov, i)) >= 0) {
	    written += len;
	    notWritten -= len;
	    todo = notWritten;
	} else if (ETEST(errno)
#ifdef SUNSYSV /* check for another brain-damaged OS bug */
		 || (errno == 0)
#endif
#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
		 || ((errno == EMSGSIZE) && (todo == 1))
#endif
		)
	{
	    FD_SET(fd, &ClientsWriteBlocked);
	    AnyClientsWriteBlocked = TRUE;

	    if (written < oco->count) {
		if (written > 0) {
		    oco->count -= written;
		    memmove( (char *) oco->buf, (char *) oco->buf + written,
			    oco->count);
		    written = 0;
		}
	    } else {
		written -= oco->count;
		oco->count = 0;
	    }

	    /* grow buffer if necessary */
	    if (notWritten > oco->size) {
		unsigned char *obuf;

		obuf = (unsigned char *) fsrealloc(oco->buf,
					      notWritten + OutputBufferSize);
		if (!obuf) {
		    if (oc->trans_conn)
			_FontTransClose(oc->trans_conn);
		    oc->trans_conn = NULL;
		    MarkClientException(client);
		    oco->count = 0;
		    return -1;
		}
		oco->size = notWritten + OutputBufferSize;
		oco->buf = obuf;
	    }
	    if ((len = extraCount - written) > 0) {
		memmove( (char *) oco->buf + oco->count, 
			extraBuf + written, len);
	    }
	    oco->count = notWritten;
	    return extraCount;
	}
#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
	else if (errno == EMSGSIZE)
	{
	    todo >>= 1;
	}
#endif
	else
	{
	    if (oc->trans_conn)
Example #2
0
File: io.c Project: theqvd/vcxsrv
int
FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
{
    ConnectionOutputPtr oco = oc->output;
    int connection = oc->fd;
    XtransConnInfo trans_conn = oc->trans_conn;
    struct iovec iov[3];
    static char padBuffer[3];
    const char *extraBuf = __extraBuf;
    long written;
    long padsize;
    long notWritten;
    long todo;

    if (!oco)
	return 0;
    written = 0;
    padsize = padding_for_int32(extraCount);
    notWritten = oco->count + extraCount + padsize;
    if (!notWritten)
        return 0;

    todo = notWritten;
    while (notWritten) {
        long before = written;  /* amount of whole thing written */
        long remain = todo;     /* amount to try this time, <= notWritten */
        int i = 0;
        long len;

        /* You could be very general here and have "in" and "out" iovecs
         * and write a loop without using a macro, but what the heck.  This
         * translates to:
         *
         *     how much of this piece is new?
         *     if more new then we are trying this time, clamp
         *     if nothing new
         *         then bump down amount already written, for next piece
         *         else put new stuff in iovec, will need all of next piece
         *
         * Note that todo had better be at least 1 or else we'll end up
         * writing 0 iovecs.
         */
#define InsertIOV(pointer, length) \
	len = (length) - before; \
	if (len > remain) \
	    len = remain; \
	if (len <= 0) { \
	    before = (-len); \
	} else { \
	    iov[i].iov_len = len; \
	    iov[i].iov_base = (pointer) + before;	\
	    i++; \
	    remain -= len; \
	    before = 0; \
	}

        InsertIOV((char *) oco->buf, oco->count)
            InsertIOV((char *) extraBuf, extraCount)
            InsertIOV(padBuffer, padsize)

            errno = 0;
        if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0) {
            written += len;
            notWritten -= len;
            todo = notWritten;
        }
        else if (ETEST(errno)
#ifdef SUNSYSV                  /* check for another brain-damaged OS bug */
                 || (errno == 0)
#endif
#ifdef EMSGSIZE                 /* check for another brain-damaged OS bug */
                 || ((errno == EMSGSIZE) && (todo == 1))
#endif
            ) {
            /* If we've arrived here, then the client is stuffed to the gills
               and not ready to accept more.  Make a note of it and buffer
               the rest. */
            errno=0;
            FD_SET(connection, &ClientsWriteBlocked);
            AnyClientsWriteBlocked = TRUE;

            if (written < oco->count) {
                if (written > 0) {
                    oco->count -= written;
                    memmove((char *) oco->buf,
                            (char *) oco->buf + written, oco->count);
                    written = 0;
                }
            }
            else {
                written -= oco->count;
                oco->count = 0;
            }

            if (notWritten > oco->size) {
                unsigned char *obuf = NULL;

                if (notWritten + BUFSIZE <= INT_MAX) {
                    obuf = realloc(oco->buf, notWritten + BUFSIZE);
                }
                if (!obuf) {
                    _XSERVTransDisconnect(oc->trans_conn);
                    _XSERVTransClose(oc->trans_conn);
                    oc->trans_conn = NULL;
                    MarkClientException(who);
                    oco->count = 0;
                    return -1;
                }
                oco->size = notWritten + BUFSIZE;
                oco->buf = obuf;
            }

            /* If the amount written extended into the padBuffer, then the
               difference "extraCount - written" may be less than 0 */
            if ((len = extraCount - written) > 0)
                memmove((char *) oco->buf + oco->count,
                        extraBuf + written, len);

            oco->count = notWritten;    /* this will include the pad */
            /* return only the amount explicitly requested */
            return extraCount;
        }
#ifdef EMSGSIZE                 /* check for another brain-damaged OS bug */
        else if (errno == EMSGSIZE) {
            todo >>= 1;
        }
#endif
        else {
            if (oc->trans_conn) {
int
ReadRequest(ClientPtr client)
{
    OsCommPtr   oc;
    ConnectionInputPtr oci;
    fsReq      *request;
    int         fd,
                result,
                gotnow,
                needed = 0;

    if (client == NULL)
	return -1;
    oc = (OsCommPtr) client->osPrivate;
    if (oc == NULL)
	return -1;
    oci = oc->input;
    fd = oc->fd;
    if (oci != NULL && fd < 0)
	return -1;
		
    if (AvailableInput) {
	if (AvailableInput != oc) {
	    ConnectionInputPtr aci = AvailableInput->input;

	    if (aci->size > BUFWATERMARK) {
		fsfree(aci->buffer);
		fsfree(aci);
	    } else {
		aci->next = FreeInputs;
		FreeInputs = aci;
	    }
	    AvailableInput->input = (ConnectionInputPtr) NULL;
	}
	AvailableInput = (OsCommPtr) NULL;
    }
    if (!oci) {
	if ((oci = FreeInputs ) != (ConnectionInputPtr) 0) {
	    FreeInputs = oci->next;
	} else if (!(oci = AllocateInputBuffer())) {
	    yield_control_death();
	    return -1;
	}
	oc->input = oci;
    }
    oci->bufptr += oci->lenLastReq;

    gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
    request = (fsReq *) oci->bufptr;

    /* not enough for a request */
    if ((gotnow < SIZEOF(fsReq)) ||
	    (gotnow < (needed = request_length(request, client)))) {
	oci->lenLastReq = 0;
	if ((gotnow < SIZEOF(fsReq)) || needed == 0)
	    needed = SIZEOF(fsReq);
	else if (needed > MAXBUFSIZE) {
	    yield_control_death();
	    return -1;
	}
	/* see if we need to shift up a partial request so the rest can fit */
	if ((gotnow == 0) ||
	    ((oci->bufptr - oci->buffer + needed) > oci->size))
	{
	    if ((gotnow > 0) && (oci->bufptr != oci->buffer))
		memmove( oci->buffer, oci->bufptr, gotnow);
	    /* grow buffer if necessary */
	    if (needed > oci->size) {
		char       *ibuf;

		ibuf = (char *) fsrealloc(oci->buffer, needed);
		if (!ibuf) {
		    yield_control_death();
		    return -1;
		}
		oci->size = needed;
		oci->buffer = ibuf;
	    }
	    oci->bufptr = oci->buffer;
	    oci->bufcnt = gotnow;
	}
	/* fill 'er up */
	if (oc->trans_conn == NULL) {
	    yield_control_death();
	    return -1;
	}
	result = _FontTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
		      oci->size - oci->bufcnt);
	if (result <= 0) {
#if !(defined(SVR4) && defined(i386) && !defined(sun))
	    if ((result < 0) && ETEST(errno)) {
		yield_control_no_input();
		return 0;
	    } else
#endif
	    {

		yield_control_death();
		return -1;
	    }
	}
	oci->bufcnt += result;
	gotnow += result;

	/* free up space after huge requests */
	if ((oci->size > BUFWATERMARK) &&
		(oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) {
	    char       *ibuf;

	    ibuf = (char *) fsrealloc(oci->buffer, BUFSIZE);
	    if (ibuf) {
		oci->size = BUFSIZE;
		oci->buffer = ibuf;
		oci->bufptr = ibuf + oci->bufcnt - gotnow;
	    }
	}
	request = (fsReq *) oci->bufptr;
	if ((gotnow < SIZEOF(fsReq)) ||
	    (gotnow < (needed = request_length(request, client)))) {
	    yield_control_no_input();
	    return 0;
	}
    }
    if (needed == 0)
	needed = SIZEOF(fsReq);
    oci->lenLastReq = needed;
    /*
     * Check to see if client has at least one whole request in the buffer. 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.
     */

    if (gotnow >= needed + SIZEOF(fsReq)) {
	request = (fsReq *) (oci->bufptr + needed);
	if (gotnow >= needed + request_length(request, client))
	    FD_SET(fd, &ClientsWithInput);
	else
	    yield_control_no_input();
    } else {
	if (gotnow == needed)
	    AvailableInput = oc;
	yield_control_no_input();
    }

    if (++timesThisConnection >= MAX_TIMES_PER)
	yield_control();

    client->requestBuffer = (pointer) oci->bufptr;
    return needed;
}
Example #4
0
File: io.c Project: 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;
}