static ssize_t readBytesFromSocket(int socketDescriptor, uint8_t* buffer, int count, int* fileDescriptors, size_t* fileDescriptorsCount) { struct msghdr message; memset(&message, 0, sizeof(message)); struct iovec iov[1]; memset(&iov, 0, sizeof(iov)); message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentMaxAmount); MallocPtr<char> attachmentDescriptorBuffer = MallocPtr<char>::malloc(sizeof(char) * message.msg_controllen); memset(attachmentDescriptorBuffer.get(), 0, sizeof(char) * message.msg_controllen); message.msg_control = attachmentDescriptorBuffer.get(); iov[0].iov_base = buffer; iov[0].iov_len = count; message.msg_iov = iov; message.msg_iovlen = 1; while (true) { ssize_t bytesRead = recvmsg(socketDescriptor, &message, 0); if (bytesRead < 0) { if (errno == EINTR) continue; return -1; } bool found = false; struct cmsghdr* controlMessage; for (controlMessage = CMSG_FIRSTHDR(&message); controlMessage; controlMessage = CMSG_NXTHDR(&message, controlMessage)) { if (controlMessage->cmsg_level == SOL_SOCKET && controlMessage->cmsg_type == SCM_RIGHTS) { *fileDescriptorsCount = (controlMessage->cmsg_len - CMSG_LEN(0)) / sizeof(int); memcpy(fileDescriptors, CMSG_DATA(controlMessage), sizeof(int) * *fileDescriptorsCount); for (size_t i = 0; i < *fileDescriptorsCount; ++i) { while (fcntl(fileDescriptors[i], F_SETFD, FD_CLOEXEC) == -1) { if (errno != EINTR) { ASSERT_NOT_REACHED(); break; } } } found = true; break; } } if (!found) *fileDescriptorsCount = 0; return bytesRead; } return -1; }
// Return false if we cannot advance the stream. Currently the only possible failure is that the underlying file has been removed or changed since File.slice. static bool advanceCurrentStream(FormStreamFields* form) { closeCurrentStream(form); if (form->remainingElements.isEmpty()) return true; // Create the new stream. FormDataElement& nextInput = form->remainingElements.last(); if (nextInput.m_type == FormDataElement::data) { size_t size = nextInput.m_data.size(); MallocPtr<char> data = nextInput.m_data.releaseBuffer(); form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data.get()), size, kCFAllocatorNull); form->currentData = std::move(data); } else { #if ENABLE(BLOB) // Check if the file has been changed or not if required. if (isValidFileTime(nextInput.m_expectedFileModificationTime)) { time_t fileModificationTime; if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime)) return false; } #endif const String& path = nextInput.m_shouldGenerateFile ? nextInput.m_generatedFilename : nextInput.m_filename; form->currentStream = CFReadStreamCreateWithFile(0, pathAsURL(path).get()); if (!form->currentStream) { // The file must have been removed or become unreadable. return false; } #if ENABLE(BLOB) if (nextInput.m_fileStart > 0) { RetainPtr<CFNumberRef> position = adoptCF(CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart)); CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get()); } form->currentStreamRangeLength = nextInput.m_fileLength; #endif } form->remainingElements.removeLast(); // Set up the callback. CFStreamClientContext context = { 0, form, 0, 0, 0 }; CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, formEventCallback, &context); // Schedule with the current set of run loops. SchedulePairHashSet::iterator end = form->scheduledRunLoopPairs.end(); for (SchedulePairHashSet::iterator it = form->scheduledRunLoopPairs.begin(); it != end; ++it) CFReadStreamScheduleWithRunLoop(form->currentStream, (*it)->runLoop(), (*it)->mode()); return true; }
bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder) { COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline); Vector<Attachment> attachments = encoder->releaseAttachments(); if (attachments.size() > (attachmentMaxAmount - 1)) { ASSERT_NOT_REACHED(); return false; } MessageInfo messageInfo(encoder->bufferSize(), attachments.size()); size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(AttachmentInfo)) + encoder->bufferSize(); if (messageSizeWithBodyInline > messageMaxSize && encoder->bufferSize()) { RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::allocate(encoder->bufferSize()); if (!oolMessageBody) return false; WebKit::SharedMemory::Handle handle; if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::Protection::ReadOnly)) return false; messageInfo.setMessageBodyIsOutOfLine(); memcpy(oolMessageBody->data(), encoder->buffer(), encoder->bufferSize()); attachments.append(handle.releaseAttachment()); } struct msghdr message; memset(&message, 0, sizeof(message)); struct iovec iov[3]; memset(&iov, 0, sizeof(iov)); message.msg_iov = iov; int iovLength = 1; iov[0].iov_base = reinterpret_cast<void*>(&messageInfo); iov[0].iov_len = sizeof(messageInfo); std::unique_ptr<AttachmentInfo[]> attachmentInfo; MallocPtr<char> attachmentFDBuffer; if (!attachments.isEmpty()) { int* fdPtr = 0; size_t attachmentFDBufferLength = std::count_if(attachments.begin(), attachments.end(), [](const Attachment& attachment) { return attachment.fileDescriptor() != -1; }); if (attachmentFDBufferLength) { attachmentFDBuffer = MallocPtr<char>::malloc(sizeof(char) * CMSG_SPACE(sizeof(int) * attachmentFDBufferLength)); message.msg_control = attachmentFDBuffer.get(); message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentFDBufferLength); memset(message.msg_control, 0, message.msg_controllen); struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int) * attachmentFDBufferLength); fdPtr = reinterpret_cast<int*>(CMSG_DATA(cmsg)); } attachmentInfo = std::make_unique<AttachmentInfo[]>(attachments.size()); int fdIndex = 0; for (size_t i = 0; i < attachments.size(); ++i) { attachmentInfo[i].setType(attachments[i].type()); switch (attachments[i].type()) { case Attachment::MappedMemoryType: attachmentInfo[i].setSize(attachments[i].size()); // Fall trhough, set file descriptor or null. case Attachment::SocketType: if (attachments[i].fileDescriptor() != -1) { ASSERT(fdPtr); fdPtr[fdIndex++] = attachments[i].fileDescriptor(); } else attachmentInfo[i].setNull(); break; case Attachment::Uninitialized: default: break; } } iov[iovLength].iov_base = attachmentInfo.get(); iov[iovLength].iov_len = sizeof(AttachmentInfo) * attachments.size(); ++iovLength; } if (!messageInfo.isMessageBodyIsOutOfLine() && encoder->bufferSize()) { iov[iovLength].iov_base = reinterpret_cast<void*>(encoder->buffer()); iov[iovLength].iov_len = encoder->bufferSize(); ++iovLength; } message.msg_iovlen = iovLength; while (sendmsg(m_socketDescriptor, &message, 0) == -1) { if (errno == EINTR) continue; if (errno == EAGAIN || errno == EWOULDBLOCK) { struct pollfd pollfd; pollfd.fd = m_socketDescriptor; pollfd.events = POLLOUT; pollfd.revents = 0; poll(&pollfd, 1, -1); continue; } WTFLogAlways("Error sending IPC message: %s", strerror(errno)); return false; } return true; }