Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9cbf987 authored by Jerry Zhang's avatar Jerry Zhang
Browse files

Fix zero length packet handling

Ensure that a zero length packet is properly sent
/ received when handling data that is a multiple of the
endpoint size.

This fixes an issue where files whose size is a multiple
of the endpoint size would hang during transfer.

Bug: 37175601
Test: check successful file transfer.
Change-Id: Iaf3cea18422234d65b59f5961ef9fb3f3ee2049a
parent f4b7240b
Loading
Loading
Loading
Loading
+26 −10
Original line number Diff line number Diff line
@@ -520,7 +520,16 @@ int MtpFfsHandle::receiveFile(mtp_file_range mfr) {
    // When receiving files, the incoming length is given in 32 bits.
    // A >4G file is given as 0xFFFFFFFF
    uint32_t file_length = mfr.length;
    uint64_t offset = lseek(mfr.fd, 0, SEEK_CUR);
    uint64_t offset = mfr.offset;
    struct usb_endpoint_descriptor mBulkOut_desc;
    int packet_size;

    if (ioctl(mBulkOut, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&mBulkOut_desc))) {
        PLOG(ERROR) << "Could not get FFS bulk-out descriptor";
        packet_size = MAX_PACKET_SIZE_HS;
    } else {
        packet_size = mBulkOut_desc.wMaxPacketSize;
    }

    char *data = mBuffer1.data();
    char *data2 = mBuffer2.data();
@@ -573,21 +582,26 @@ int MtpFfsHandle::receiveFile(mtp_file_range mfr) {
        }

        if (read) {
            // Enqueue a new write request
            aio.aio_buf = data;
            aio.aio_sink = mfr.fd;
            aio.aio_offset = offset;
            aio.aio_nbytes = ret;
            aio_write(&aio);

            if (file_length == MAX_MTP_FILE_SIZE) {
                // For larger files, receive until a short packet is received.
                if (static_cast<size_t>(ret) < length) {
                    file_length = 0;
                }
            } else {
                // Receive an empty packet if size is a multiple of the endpoint size.
                file_length -= ret;
                if (file_length == 0 && ret % packet_size == 0) {
                    if (TEMP_FAILURE_RETRY(::read(mBulkOut, data, packet_size)) != 0) {
                        return -1;
                    }
                }
            }
            // Enqueue a new write request
            aio.aio_buf = data;
            aio.aio_sink = mfr.fd;
            aio.aio_offset = offset;
            aio.aio_nbytes = ret;
            aio_write(&aio);

            offset += ret;
            std::swap(data, data2);
@@ -695,9 +709,11 @@ int MtpFfsHandle::sendFile(mtp_file_range mfr) {
        }
    }

    if (given_length == MAX_MTP_FILE_SIZE && ret % packet_size == 0) {
    if (ret % packet_size == 0) {
        // If the last packet wasn't short, send a final empty packet
        if (writeHandle(mBulkIn, data, 0) == -1) return -1;
        if (TEMP_FAILURE_RETRY(::write(mBulkIn, data, 0)) != 0) {
            return -1;
        }
    }

    return 0;