/* * Reads the header of the message to determine whether to call RecvRequest or * RecvResponse. */ static ssize_t SrpcPeekMessage(struct NaClSrpcMessageChannel* channel, NaClSrpcRpc* rpc) { struct NaClImcMsgIoVec iov[1]; const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov); size_t iov_len; NaClSrpcMessageHeader header; size_t expected_bytes; ssize_t retval; iov_len = 0; expected_bytes = 0; AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes); header.iov = iov; header.iov_length = NACL_ARRAY_SIZE(iov); header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL; header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0; retval = NaClSrpcMessageChannelPeek(channel, &header); /* * Check that the peek read the RPC and that the argument lengths are sane. */ if (retval < (ssize_t) expected_bytes) { retval = ErrnoFromImcRet(retval); } else if (rpc->value_len > NACL_SRPC_MAX_ARGS || rpc->template_len > NACL_SRPC_MAX_ARGS) { retval = -NACL_ABI_EIO; } return retval; }
static ssize_t RecvResponse(struct NaClSrpcMessageChannel* channel, NaClSrpcRpc* rpc, NaClSrpcArg** results) { NaClSrpcArg* result_copy[NACL_SRPC_MAX_ARGS + 1]; struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX]; const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov); size_t iov_len = 0; NaClSrpcMessageHeader header; NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS]; size_t expected_bytes; ssize_t retval; size_t i; if (results == NULL) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvResponse: results should not be NULL\n"); retval = -NACL_ABI_EINVAL; goto done; } /* * SrpcPeekMessage should have been called before this function, and should * have populated rpc. Make sure that rpc points to a sane header. */ if (rpc->is_request || rpc->template_len > 0 || rpc->value_len > NACL_SRPC_MAX_ARGS || rpc->value_len != VectorLen(results)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvResponse: rpc header invalid: is_request %"NACL_PRIu32", " "template_len %"NACL_PRIu32", value_len %"NACL_PRIu32"\n", rpc->is_request, rpc->template_len, rpc->value_len); return -NACL_ABI_EINVAL; } /* * Having read the header we know how many elements the results vector * contains. The next peek reads the fixed portion of the results vectors, * but cannot yet read the variable length portion, because we do not yet * know the counts of array types or strings. Because the results read * could conflict with the expected types, we need to read the fixed portion * into a copy. */ if (!AllocateArgs(result_copy, rpc->value_len)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvResponse: AllocateArgs failed\n"); retval = -NACL_ABI_EINVAL; goto done; } iov_len = 0; expected_bytes = 0; AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes); for (i = 0; i < rpc->value_len; ++i) { AddIovEntry(result_copy[i], kArgSize, kMaxIovLen, iov, &iov_len, &expected_bytes); } header.iov = iov; header.iov_length = (nacl_abi_size_t) iov_len; header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL; header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0; retval = NaClSrpcMessageChannelPeek(channel, &header); if (retval < (ssize_t) expected_bytes) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvResponse: NaClSrpcMessageChannelPeek incomplete: " "expected %"NACL_PRIdS", got %"NACL_PRIdS"\n", expected_bytes, retval); retval = ErrnoFromImcRet(retval); goto done; } /* * Check that the peeked results vector's types conform to the types passed * in and that any nonfixed size arguments are no larger than the counts * passed in from the caller. If the values are acceptable, we copy the * actual sizes to the caller's vector. */ if (!CheckMatchAndCopyCounts(rpc->value_len, results, result_copy)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvResponse: CheckMatchAndCopyCounts failed\n"); retval = -NACL_ABI_EIO; goto done; } /* * After peeking the fixed portion of the results vector we are ready to * read the nonfixed portion as well. So the read just adds the IOV entries * for the nonfixed portion of results. */ iov_len = 0; expected_bytes = 0; AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes); AddFixed(results, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes); if (!AddNonfixedForRead(results, rpc->value_len, kMaxIovLen, 0, 1, iov, &iov_len, &expected_bytes)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvResponse: AddNonfixedForRead failed\n"); retval = -NACL_ABI_EIO; goto done; } header.iov = iov; header.iov_length = (nacl_abi_size_t) iov_len; header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs; header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs); retval = NaClSrpcMessageChannelReceive(channel, &header); if (retval < (ssize_t) expected_bytes) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvResponse: NaClSrpcMessageChannelReceive incomplete: " "expected %"NACL_PRIdS", got %"NACL_PRIdS"\n", expected_bytes, retval); retval = ErrnoFromImcRet(retval); goto done; } /* * The read left any descriptors returned in the descs array. We need to * copy those descriptors to the results vector. */ if (!GetHandles(results, rpc->value_len, descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvResponse: GetHandles failed\n"); retval = -NACL_ABI_EIO; } done: FreeArgs(result_copy); return retval; }
static ssize_t RecvRequest(struct NaClSrpcMessageChannel* channel, NaClSrpcRpc* rpc, NaClSrpcArg** inputs, NaClSrpcArg** results) { struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX]; const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov); size_t iov_len; NaClSrpcMessageHeader header; NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS]; size_t expected_bytes; ssize_t retval; /* * SrpcPeekMessage should have been called before this function, and should * have populated rpc. Make sure that rpc points to a sane header. */ if (!rpc->is_request || rpc->template_len > NACL_SRPC_MAX_ARGS || rpc->value_len > NACL_SRPC_MAX_ARGS) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvRequest: rpc header invalid: is_request %"NACL_PRIu32", " "template_len %"NACL_PRIu32", value_len %"NACL_PRIu32"\n", rpc->is_request, rpc->template_len, rpc->value_len); retval = -NACL_ABI_EINVAL; goto done; } /* * A request will contain two vectors of NaClSrpcArgs. Set the index * pointers passed in to new argument vectors that will be filled during * the next peek. */ if (!AllocateArgs(results, rpc->template_len) || !AllocateArgs(inputs, rpc->value_len)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvRequest: AllocateArgs failed\n"); retval = -NACL_ABI_EINVAL; goto done; } /* * Having read the header we know how many elements each argument vector * contains. The next peek reads the fixed portion of these argument vectors, * but cannot yet read the variable length portion, because we do not yet * know the counts of array types or strings. */ iov_len = 0; expected_bytes = 0; AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes); AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len, &expected_bytes); AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes); header.iov = iov; header.iov_length = (nacl_abi_size_t) iov_len; header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL; header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0; retval = NaClSrpcMessageChannelPeek(channel, &header); if (retval < (ssize_t) expected_bytes) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvRequest:" "NaClSrpcMessageChannelPeek incomplete: expected %" NACL_PRIdS", got %"NACL_PRIdS"\n", expected_bytes, retval); retval = ErrnoFromImcRet(retval); goto done; } /* * After peeking the fixed portion of the argument vectors we are ready to * read the nonfixed portions as well. So the read just adds the IOV entries * for the nonfixed portions of the arguments. */ iov_len = 0; expected_bytes = 0; AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes); ClearTemplateStringLengths(results, rpc->template_len); AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len, &expected_bytes); AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes); if (!AddNonfixedForRead(results, rpc->template_len, kMaxIovLen, 1, 0, iov, &iov_len, &expected_bytes)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvRequest: AllocateArgs failed for results\n"); retval = -NACL_ABI_EIO; goto done; } if (!AddNonfixedForRead(inputs, rpc->value_len, kMaxIovLen, 1, 1, iov, &iov_len, &expected_bytes)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvRequest: AllocateArgs failed for inputs\n"); retval = -NACL_ABI_EIO; goto done; } header.iov = iov; header.iov_length = (nacl_abi_size_t) iov_len; header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs; header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs); retval = NaClSrpcMessageChannelReceive(channel, &header); if (retval < (ssize_t) expected_bytes) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvRequest:" " NaClSrpcMessageChannelReceive incomplete: expected %" NACL_PRIdS", got %"NACL_PRIdS"\n", expected_bytes, retval); retval = ErrnoFromImcRet(retval); goto done; } /* * The read left any descriptors passed in the descs array. We need to * copy those descriptors to the inputs vector. */ if (!GetHandles(inputs, rpc->value_len, descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RecvRequest: GetHandles failed\n"); retval = -NACL_ABI_EIO; goto done; } /* * Success, the caller has taken ownership of the memory we allocated * for inputs and results. */ inputs = NULL; results = NULL; done: FreeArgs(inputs); FreeArgs(results); return retval; }
/* * Sends message over the channel. It returns 1 if successful, or 0 otherwise. */ ssize_t NaClSrpcMessageChannelSend(struct NaClSrpcMessageChannel* channel, const NaClSrpcMessageHeader* header) { ssize_t imc_ret; struct NaClImcMsgIoVec* iovec = NULL; NaClSrpcMessageHeader remaining; NaClSrpcMessageHeader frag_hdr; LengthHeader total_size; LengthHeader fragment_size; size_t expected_bytes_sent; ssize_t retval = -NACL_ABI_EINVAL; iovec = CopyAndAddIovs(header->iov, header->iov_length, 2); if (NULL == iovec) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend: CopyAndAddIovs failed.\n"); goto done; } remaining.iov = iovec; remaining.iov_length = header->iov_length + 2; remaining.NACL_SRPC_MESSAGE_HEADER_DESCV = header->NACL_SRPC_MESSAGE_HEADER_DESCV; remaining.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH; remaining.iov[0].base = &total_size; remaining.iov[0].length = sizeof total_size; remaining.iov[1].base = &fragment_size; remaining.iov[1].length = sizeof fragment_size; if (-1 == HeaderTotalBytes(&remaining, 0)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend: header size overflow.\n"); goto done; } /* * Send the first (possibly only) fragment. * HeaderTotalBytes returns -1 if the total is greater than * NACL_ABI_SSIZE_T_MAX. */ total_size.byte_count = (nacl_abi_size_t) HeaderTotalBytes(&remaining, 2); if (-1 == (nacl_abi_ssize_t) total_size.byte_count) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend: HeaderTotalBytes failed.\n"); goto done; } total_size.desc_count = header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH; /* * Compute the first fragment's message descriptor and fragment descriptor, * limiting the bytes and descriptors sent in the first fragment to preset * amounts. */ if (!ComputeFragmentSizes(&remaining, FIRST_FRAGMENT, &fragment_size)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend:" " first ComputeFragmentSize failed.\n"); goto done; } NaClSrpcLog(3, "NaClSrpcMessageChannelSend: new message, bytes %" NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n", total_size.byte_count, total_size.desc_count); NaClSrpcLog(3, "NaClSrpcMessageChannelSend: first fragment, bytes %" NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n", fragment_size.byte_count, fragment_size.desc_count); if (NACL_ABI_SSIZE_T_MAX - kFragmentOverhead[FIRST_FRAGMENT] < fragment_size.byte_count) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend:" " fragment size would cause overflow.\n"); goto done; } expected_bytes_sent = fragment_size.byte_count + kFragmentOverhead[FIRST_FRAGMENT]; if (expected_bytes_sent > NaClSrpcMaxImcSendmsgSize) { NaClSrpcLog(NACL_SRPC_LOG_FATAL, "NaClSrpcMessageChannelSend: expected bytes %" NACL_PRIdS" exceed maximum allowed %"NACL_PRIdNACL_SIZE"\n", expected_bytes_sent, NaClSrpcMaxImcSendmsgSize); } if (!BuildFragmentHeader(&remaining, &fragment_size, 2, &frag_hdr)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend:" " could not build fragment header.\n"); goto done; } /* * The first message has at least three iov entries: one for the (message) * total_size descriptor, one for the fragment_size descriptor, and at * least one for the first fragment's bytes and descs. */ imc_ret = ImcSendmsg(channel->desc.raw_desc, &frag_hdr, 0); free(frag_hdr.iov); if ((size_t) imc_ret != expected_bytes_sent) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend: first send failed, %" NACL_PRIdS" != %"NACL_PRIdS".\n", expected_bytes_sent, imc_ret); retval = ErrnoFromImcRet(imc_ret); goto done; } ConsumeFragment(&remaining, &fragment_size, 2); NaClSrpcLog(3, "NaClSrpcMessageChannelSend: first send succeeded.\n"); /* * Each subsequent fragment contains the bytes starting at next_byte and * the descs starting at next_desc. */ while (remaining.iov_length > 0 || remaining.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH > 0) { NaClSrpcMessageHeader frag_hdr; /* * Each subsequent message has two iov entries: one for the fragment_size * descriptor, and one for the fragment's bytes and descs. * We add the fragment length descriptor to the preceding iov entry, * which is safe, because we know that ConsumeFragment always consumes * at least the fragment length descriptor from last time. */ remaining.iov = remaining.iov - 1; remaining.iov_length = remaining.iov_length + 1; remaining.iov[0].base = &fragment_size; remaining.iov[0].length = sizeof fragment_size; if (-1 == HeaderTotalBytes(&remaining, 0)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend: header size overflow.\n"); goto done; } /* * The fragment sizes are again limited. */ if (!ComputeFragmentSizes(&remaining, LATER_FRAGMENT, &fragment_size)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend:" " other ComputeFragmentSize failed.\n"); retval = -NACL_ABI_EIO; goto done; } NaClSrpcLog(3, "NaClSrpcMessageChannelSend: next fragment, bytes %" NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n", fragment_size.byte_count, fragment_size.desc_count); if (!BuildFragmentHeader(&remaining, &fragment_size, 1, &frag_hdr)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend:" " could not build fragment header.\n"); retval = -NACL_ABI_EIO; goto done; } /* * Send the fragment. */ if (NACL_ABI_SSIZE_T_MAX - kFragmentOverhead[LATER_FRAGMENT] < fragment_size.byte_count) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend:" " fragment size would cause overflow.\n"); goto done; } expected_bytes_sent = fragment_size.byte_count + kFragmentOverhead[LATER_FRAGMENT]; if (expected_bytes_sent > NaClSrpcMaxImcSendmsgSize) { NaClSrpcLog(NACL_SRPC_LOG_FATAL, "NaClSrpcMessageChannelSend: expected bytes %" NACL_PRIdS" exceed maximum allowed %"NACL_PRIdNACL_SIZE"\n", expected_bytes_sent, NaClSrpcMaxImcSendmsgSize); } imc_ret = ImcSendmsg(channel->desc.raw_desc, &frag_hdr, 0); free(frag_hdr.iov); if ((size_t) imc_ret != expected_bytes_sent) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelSend: send error.\n"); retval = ErrnoFromImcRet(imc_ret); goto done; } ConsumeFragment(&remaining, &fragment_size, 1); } NaClSrpcLog(3, "NaClSrpcMessageChannelSend: complete send, sent %" NACL_PRIdNACL_SIZE" bytes and %"NACL_PRIdNACL_SIZE" descs.\n", total_size.byte_count, total_size.desc_count); retval = (ssize_t) total_size.byte_count; done: free(iovec); return retval; }
/* * Receive a message from channel. On success it returns the number of * bytes read; otherwise, returns -1. */ ssize_t NaClSrpcMessageChannelReceive(struct NaClSrpcMessageChannel* channel, NaClSrpcMessageHeader* header) { /* * TODO(sehr): A large prefix of this function is common with Peek. * Find a way to merge them. */ ssize_t imc_ret = -1; NaClSrpcMessageHeader header_copy; struct NaClImcMsgIoVec* iovec = NULL; LengthHeader total_size; LengthHeader fragment_size; LengthHeader processed_size; size_t bytes_received; size_t descs_received; ssize_t retval = -NACL_ABI_EINVAL; NaClSrpcLog(3, "NaClSrpcMessageChannelReceive: waiting for message.\n"); /* * The first fragment consists of two LengthHeaders and a fraction of the * bytes (starting at 0) and the fraction of descs (starting at 0). */ iovec = CopyAndAddIovs(header->iov, header->iov_length, 2); if (NULL == iovec) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelReceive: CopyAndAddIovs failed.\n"); goto done; } header_copy.iov = iovec; header_copy.iov_length = header->iov_length + 2; header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV = header->NACL_SRPC_MESSAGE_HEADER_DESCV; /* SRPC_DESC_MAX <= NACL_ABI_SIZE_T_MAX, so the cast is safe. */ header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t) size_min(SRPC_DESC_MAX, header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH); header_copy.iov[0].base = &total_size; header_copy.iov[0].length = sizeof total_size; header_copy.iov[1].base = &fragment_size; header_copy.iov[1].length = sizeof fragment_size; header_copy.flags = 0; if (-1 == HeaderTotalBytes(&header_copy, 0)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelReceive: header size overflow.\n"); goto done; } /* * The message receive should return at least * kFragmentOverhead[FIRST_FRAGMENT] bytes. */ imc_ret = MessageChannelBufferRead(channel, &header_copy, 0); if (imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelReceive: read failed (%"NACL_PRIdS").\n", imc_ret); retval = ErrnoFromImcRet(imc_ret); goto done; } /* Comparison above guarantees no underflow. */ bytes_received = imc_ret - kFragmentOverhead[FIRST_FRAGMENT]; descs_received = header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH; if (!MessageLengthsAreSane( &total_size, &fragment_size, (size_t) imc_ret, header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelReceive:" " first fragment descriptor check failed.\n"); retval = -NACL_ABI_EIO; goto done; } NaClSrpcLog(3, "NaClSrpcMessageChannelReceive:" " new message, bytes %"NACL_PRIdNACL_SIZE ", descs %"NACL_PRIdNACL_SIZE".\n", total_size.byte_count, total_size.desc_count); NaClSrpcLog(3, "NaClSrpcMessageChannelReceive:" " first fragment, bytes %"NACL_PRIdNACL_SIZE ", descs %"NACL_PRIdNACL_SIZE".\n", fragment_size.byte_count, fragment_size.desc_count); processed_size = fragment_size; ConsumeFragment(&header_copy, &fragment_size, 2); /* * Get the remaining fragments. */ while (processed_size.byte_count < total_size.byte_count || processed_size.desc_count < total_size.desc_count) { /* * The non-first fragments consist of a single LengthHeader and a * portion of the remaining iov entries and descv entries. We add the * fragment length descriptor to the preceding iov entry, which is safe, * because we know that ConsumeFragment always consumes at least the * fragment length descriptor from last time. */ header_copy.iov = header_copy.iov - 1; header_copy.iov_length = header_copy.iov_length + 1; header_copy.iov[0].base = &fragment_size; header_copy.iov[0].length = sizeof fragment_size; header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV = header->NACL_SRPC_MESSAGE_HEADER_DESCV + descs_received; header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t) size_min(SRPC_DESC_MAX, (header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH - descs_received)); if (-1 == HeaderTotalBytes(&header_copy, 0)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelReceive: header size overflow.\n"); goto done; } /* * The message receive should return at least * kFragmentOverhead[LATER_FRAGMENT] bytes. This is needed to make sure * that we can correctly maintain the index into bytes and descs. */ imc_ret = ImcRecvmsg(channel->desc.raw_desc, &header_copy, 0); if (imc_ret < (ssize_t) kFragmentOverhead[LATER_FRAGMENT]) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelReceive: read failed (%" NACL_PRIdS").\n", imc_ret); retval = ErrnoFromImcRet(imc_ret); goto done; } /* Comparison above guarantees no underflow. */ bytes_received += imc_ret - kFragmentOverhead[LATER_FRAGMENT]; descs_received += header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH; if (!FragmentLengthIsSane( &fragment_size, (size_t) imc_ret, header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelReceive:" " other fragment descriptor check failed.\n"); retval = -NACL_ABI_EIO; goto done; } NaClSrpcLog(3, "NaClSrpcMessageChannelReceive:" " next fragment, bytes %"NACL_PRIdNACL_SIZE ", descs %"NACL_PRIdNACL_SIZE".\n", fragment_size.byte_count, fragment_size.desc_count); processed_size.byte_count += fragment_size.byte_count; processed_size.desc_count += fragment_size.desc_count; ConsumeFragment(&header_copy, &fragment_size, 1); } NaClSrpcLog(3, "NaClSrpcMessageChannelReceive:" " succeeded, read %"NACL_PRIdS" bytes and %" NACL_PRIdNACL_SIZE" descs.\n", bytes_received, processed_size.desc_count); retval = (ssize_t) bytes_received; header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t) descs_received; header->flags = header_copy.flags; done: free(iovec); return retval; }
/* * Peek a message from channel. Reads the first fragment of the message and * leaves it available for future calls to Peek or Receive. */ ssize_t NaClSrpcMessageChannelPeek(struct NaClSrpcMessageChannel* channel, NaClSrpcMessageHeader* header) { /* * TODO(sehr): Most of this function is common with Receive. * Find a way to merge them. */ struct NaClImcMsgIoVec* iovec = NULL; NaClSrpcMessageHeader header_copy; LengthHeader total_size; LengthHeader fragment_size; ssize_t imc_ret; ssize_t retval = -NACL_ABI_EINVAL; /* Append the fragment headers to the iov. */ iovec = CopyAndAddIovs(header->iov, header->iov_length, 2); if (NULL == iovec) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelPeek: CopyAndAddIovs failed.\n"); return -1; } header_copy.iov = iovec; header_copy.iov_length = header->iov_length + 2; header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV = header->NACL_SRPC_MESSAGE_HEADER_DESCV; /* SRPC_DESC_MAX <= NACL_ABI_SIZE_T_MAX, so the cast is safe. */ header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t) size_min(SRPC_DESC_MAX, header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH); header_copy.iov[0].base = &total_size; header_copy.iov[0].length = sizeof total_size; header_copy.iov[1].base = &fragment_size; header_copy.iov[1].length = sizeof fragment_size; header_copy.flags = 0; if (-1 == HeaderTotalBytes(&header_copy, 0)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelPeek: header size overflow.\n"); goto done; } NaClSrpcLog(3, "NaClSrpcMessageChannelPeek: read message bytes %" NACL_PRIdS", descs %"NACL_PRIdS".\n", channel->byte_count, channel->desc_count); imc_ret = MessageChannelBufferRead(channel, &header_copy, 1); if (imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) { NaClSrpcLog(3, "NaClSrpcMessageChannelPeek: read failed (%"NACL_PRIdS").\n", imc_ret); retval = ErrnoFromImcRet(imc_ret); goto done; } header->flags = header_copy.flags; header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH; NaClSrpcLog(3, "NaClSrpcMessageChannelPeek: flags %x.\n", header->flags); if (!MessageLengthsAreSane( &total_size, &fragment_size, (size_t) imc_ret, header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) { NaClSrpcLog(NACL_SRPC_LOG_ERROR, "NaClSrpcMessageChannelPeek: message length mismatch.\n"); retval = -NACL_ABI_EIO; goto done; } /* Comparison above guarantees no underflow. */ retval = imc_ret - kFragmentOverhead[FIRST_FRAGMENT]; done: free(iovec); return retval; }