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