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;
}
Example #3
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;
}