Esempio n. 1
0
File: io.c Progetto: 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
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)
Esempio n. 3
0
File: io.c Progetto: theqvd/vcxsrv
int
WriteToClient(ClientPtr who, int count, const void *__buf)
{
    OsCommPtr oc;
    ConnectionOutputPtr oco;
    int padBytes;
    const char *buf = __buf;

#ifdef DEBUG_COMMUNICATION
    Bool multicount = FALSE;
#endif
    if (!count || !who || who == serverClient || who->clientGone)
        return 0;
    oc = who->osPrivate;
    oco = oc->output;
#ifdef DEBUG_COMMUNICATION
    {
        char info[128];
        xError *err;
        xGenericReply *rep;
        xEvent *ev;

        if (!who->replyBytesRemaining) {
            switch (buf[0]) {
            case X_Reply:
                rep = (xGenericReply *) buf;
                if (rep->sequenceNumber == who->sequence) {
                    snprintf(info, 127, "Xreply: type: 0x%x data: 0x%x "
                             "len: %i seq#: 0x%x", rep->type, rep->data1,
                             rep->length, rep->sequenceNumber);
                    multicount = TRUE;
                }
                break;
            case X_Error:
                err = (xError *) buf;
                snprintf(info, 127, "Xerror: Code: 0x%x resID: 0x%x maj: 0x%x "
                         "min: %x", err->errorCode, err->resourceID,
                         err->minorCode, err->majorCode);
                break;
            default:
                if ((buf[0] & 0x7f) == KeymapNotify)
                    snprintf(info, 127, "KeymapNotifyEvent: %i", buf[0]);
                else {
                    ev = (xEvent *) buf;
                    snprintf(info, 127, "XEvent: type: 0x%x detail: 0x%x "
                             "seq#: 0x%x", ev->u.u.type, ev->u.u.detail,
                             ev->u.u.sequenceNumber);
                }
            }
            ErrorF("REPLY: ClientIDX: %i %s\n", who->index, info);
        }
        else
            multicount = TRUE;
    }
#endif

    if (!oco) {
        if ((oco = FreeOutputs)) {
            FreeOutputs = oco->next;
        }
        else if (!(oco = AllocateOutputBuffer())) {
            if (oc->trans_conn) {
                _XSERVTransDisconnect(oc->trans_conn);
                _XSERVTransClose(oc->trans_conn);
                oc->trans_conn = NULL;
            }
            MarkClientException(who);
            return -1;
        }
        oc->output = oco;
    }

    padBytes = padding_for_int32(count);

    if (ReplyCallback) {
        ReplyInfoRec replyinfo;

        replyinfo.client = who;
        replyinfo.replyData = buf;
        replyinfo.dataLenBytes = count + padBytes;
        replyinfo.padBytes = padBytes;
        if (who->replyBytesRemaining) { /* still sending data of an earlier reply */
            who->replyBytesRemaining -= count + padBytes;
            replyinfo.startOfReply = FALSE;
            replyinfo.bytesRemaining = who->replyBytesRemaining;
            CallCallbacks((&ReplyCallback), (void *) &replyinfo);
        }
        else if (who->clientState == ClientStateRunning && buf[0] == X_Reply) { /* start of new reply */
            CARD32 replylen;
            unsigned long bytesleft;

            replylen = ((const xGenericReply *) buf)->length;
            if (who->swapped)
                swapl(&replylen);
            bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
            replyinfo.startOfReply = TRUE;
            replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
            CallCallbacks((&ReplyCallback), (void *) &replyinfo);
        }
    }
#ifdef DEBUG_COMMUNICATION
    else if (multicount) {
        if (who->replyBytesRemaining) {
            who->replyBytesRemaining -= (count + padBytes);
        }
        else {
            CARD32 replylen;

            replylen = ((xGenericReply *) buf)->length;
            who->replyBytesRemaining =
                (replylen * 4) + SIZEOF(xReply) - count - padBytes;
        }
    }
#endif
    if (oco->count == 0 || oco->count + count + padBytes > oco->size) {
        FD_CLR(oc->fd, &OutputPending);
        if (!XFD_ANYSET(&OutputPending)) {
            CriticalOutputPending = FALSE;
            NewOutputPending = FALSE;
        }

        if (FlushCallback)
            CallCallbacks(&FlushCallback, NULL);

        return FlushClient(who, oc, buf, count);
    }

    NewOutputPending = TRUE;
    FD_SET(oc->fd, &OutputPending);
    memmove((char *) oco->buf + oco->count, buf, count);
    oco->count += count;
    if (padBytes) {
        memset(oco->buf + oco->count, '\0', padBytes);
        oco->count += padBytes;
    }
    return count;
}