static int proc_dri3_pixmap_from_buffer(ClientPtr client) { REQUEST(xDRI3PixmapFromBufferReq); int fd; DrawablePtr drawable; PixmapPtr pixmap; int rc; SetReqFds(client, 1); REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq); LEGAL_NEW_RESOURCE(stuff->pixmap, client); rc = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess); if (rc != Success) { client->errorValue = stuff->drawable; return rc; } if (!stuff->width || !stuff->height) { client->errorValue = 0; return BadValue; } if (stuff->width > 32767 || stuff->height > 32767) return BadAlloc; if (stuff->depth != 1) { DepthPtr depth = drawable->pScreen->allowedDepths; int i; for (i = 0; i < drawable->pScreen->numDepths; i++, depth++) if (depth->depth == stuff->depth) break; if (i == drawable->pScreen->numDepths) { client->errorValue = stuff->depth; return BadValue; } } fd = ReadFdFromClient(client); if (fd < 0) return BadValue; rc = dri3_pixmap_from_fd(&pixmap, drawable->pScreen, fd, stuff->width, stuff->height, stuff->stride, stuff->depth, stuff->bpp); close (fd); if (rc != Success) return rc; pixmap->drawable.id = stuff->pixmap; /* security creation/labeling check */ rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP, pixmap, RT_NONE, NULL, DixCreateAccess); if (rc != Success) { (*drawable->pScreen->DestroyPixmap) (pixmap); return rc; } if (AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap)) return Success; return Success; }
static int proc_dri3_buffer_from_pixmap(ClientPtr client) { REQUEST(xDRI3BufferFromPixmapReq); xDRI3BufferFromPixmapReply rep = { .type = X_Reply, .nfd = 1, .sequenceNumber = client->sequence, .length = 0, }; int rc; int fd; PixmapPtr pixmap; REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq); rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP, client, DixWriteAccess); if (rc != Success) { client->errorValue = stuff->pixmap; return rc; } rep.width = pixmap->drawable.width; rep.height = pixmap->drawable.height; rep.depth = pixmap->drawable.depth; rep.bpp = pixmap->drawable.bitsPerPixel; rc = dri3_fd_from_pixmap(&fd, pixmap, &rep.stride, &rep.size); if (rc != Success) return rc; if (client->swapped) { swaps(&rep.sequenceNumber); swapl(&rep.length); swapl(&rep.size); swaps(&rep.width); swaps(&rep.height); swaps(&rep.stride); } if (WriteFdToClient(client, fd, TRUE) < 0) { close(fd); return BadAlloc; } WriteToClient(client, sizeof(rep), &rep); return client->noClientException; } static int proc_dri3_fence_from_fd(ClientPtr client) { REQUEST(xDRI3FenceFromFDReq); DrawablePtr drawable; int fd; int status; SetReqFds(client, 1); REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq); LEGAL_NEW_RESOURCE(stuff->fence, client); status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess); if (status != Success) return status; fd = ReadFdFromClient(client); if (fd < 0) return BadValue; status = SyncCreateFenceFromFD(client, drawable, stuff->fence, fd, stuff->initially_triggered); return status; }
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; }