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)
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; }