1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 4 * Copyright (C) 2011 Igalia S.L. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 25 * THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29#include "Connection.h" 30 31#include "DataReference.h" 32#include "SharedMemory.h" 33#include <sys/socket.h> 34#include <unistd.h> 35#include <errno.h> 36#include <fcntl.h> 37#include <poll.h> 38#include <wtf/Assertions.h> 39#include <wtf/Functional.h> 40#include <wtf/StdLibExtras.h> 41#include <wtf/UniStdExtras.h> 42 43#if PLATFORM(GTK) 44#include <glib.h> 45#endif 46 47#ifdef SOCK_SEQPACKET 48#define SOCKET_TYPE SOCK_SEQPACKET 49#else 50#if PLATFORM(GTK) 51#define SOCKET_TYPE SOCK_STREAM 52#else 53#define SOCKET_TYPE SOCK_DGRAM 54#endif 55#endif // SOCK_SEQPACKET 56 57namespace IPC { 58 59static const size_t messageMaxSize = 4096; 60static const size_t attachmentMaxAmount = 255; 61 62enum { 63 MessageBodyIsOutOfLine = 1U << 31 64}; 65 66class MessageInfo { 67public: 68 MessageInfo() { } 69 70 MessageInfo(size_t bodySize, size_t initialAttachmentCount) 71 : m_bodySize(bodySize) 72 , m_attachmentCount(initialAttachmentCount) 73 , m_isMessageBodyOutOfLine(false) 74 { 75 } 76 77 void setMessageBodyIsOutOfLine() 78 { 79 ASSERT(!isMessageBodyIsOutOfLine()); 80 81 m_isMessageBodyOutOfLine = true; 82 m_attachmentCount++; 83 } 84 85 bool isMessageBodyIsOutOfLine() const { return m_isMessageBodyOutOfLine; } 86 87 size_t bodySize() const { return m_bodySize; } 88 89 size_t attachmentCount() const { return m_attachmentCount; } 90 91private: 92 size_t m_bodySize; 93 size_t m_attachmentCount; 94 bool m_isMessageBodyOutOfLine; 95}; 96 97class AttachmentInfo { 98public: 99 AttachmentInfo() 100 : m_type(Attachment::Uninitialized) 101 , m_size(0) 102 , m_isNull(false) 103 { 104 } 105 106 void setType(Attachment::Type type) { m_type = type; } 107 Attachment::Type getType() { return m_type; } 108 void setSize(size_t size) 109 { 110 ASSERT(m_type == Attachment::MappedMemoryType); 111 m_size = size; 112 } 113 114 size_t getSize() 115 { 116 ASSERT(m_type == Attachment::MappedMemoryType); 117 return m_size; 118 } 119 120 // The attachment is not null unless explicitly set. 121 void setNull() { m_isNull = true; } 122 bool isNull() { return m_isNull; } 123 124private: 125 Attachment::Type m_type; 126 size_t m_size; 127 bool m_isNull; 128}; 129 130void Connection::platformInitialize(Identifier identifier) 131{ 132 m_socketDescriptor = identifier; 133 m_readBuffer.resize(messageMaxSize); 134 m_readBufferSize = 0; 135 m_fileDescriptors.resize(attachmentMaxAmount); 136 m_fileDescriptorsSize = 0; 137} 138 139void Connection::platformInvalidate() 140{ 141 // In GTK+ platform the socket is closed by the work queue. 142#if !PLATFORM(GTK) 143 if (m_socketDescriptor != -1) 144 closeWithRetry(m_socketDescriptor); 145#endif 146 147 if (!m_isConnected) 148 return; 149 150#if PLATFORM(GTK) || PLATFORM(EFL) 151 m_connectionQueue->unregisterSocketEventHandler(m_socketDescriptor); 152#endif 153 154 m_socketDescriptor = -1; 155 m_isConnected = false; 156} 157 158template<class T, class iterator> 159class AttachmentResourceGuard { 160public: 161 AttachmentResourceGuard(T& attachments) 162 : m_attachments(attachments) 163 { 164 } 165 ~AttachmentResourceGuard() 166 { 167 iterator end = m_attachments.end(); 168 for (iterator i = m_attachments.begin(); i != end; ++i) 169 i->dispose(); 170 } 171private: 172 T& m_attachments; 173}; 174 175bool Connection::processMessage() 176{ 177 if (m_readBufferSize < sizeof(MessageInfo)) 178 return false; 179 180 uint8_t* messageData = m_readBuffer.data(); 181 MessageInfo messageInfo; 182 memcpy(&messageInfo, messageData, sizeof(messageInfo)); 183 messageData += sizeof(messageInfo); 184 185 size_t messageLength = sizeof(MessageInfo) + messageInfo.attachmentCount() * sizeof(AttachmentInfo) + (messageInfo.isMessageBodyIsOutOfLine() ? 0 : messageInfo.bodySize()); 186 if (m_readBufferSize < messageLength) 187 return false; 188 189 size_t attachmentFileDescriptorCount = 0; 190 size_t attachmentCount = messageInfo.attachmentCount(); 191 std::unique_ptr<AttachmentInfo[]> attachmentInfo; 192 193 if (attachmentCount) { 194 attachmentInfo = std::make_unique<AttachmentInfo[]>(attachmentCount); 195 memcpy(attachmentInfo.get(), messageData, sizeof(AttachmentInfo) * attachmentCount); 196 messageData += sizeof(AttachmentInfo) * attachmentCount; 197 198 for (size_t i = 0; i < attachmentCount; ++i) { 199 switch (attachmentInfo[i].getType()) { 200 case Attachment::MappedMemoryType: 201 case Attachment::SocketType: 202 if (!attachmentInfo[i].isNull()) 203 attachmentFileDescriptorCount++; 204 break; 205 case Attachment::Uninitialized: 206 default: 207 ASSERT_NOT_REACHED(); 208 break; 209 } 210 } 211 212 if (messageInfo.isMessageBodyIsOutOfLine()) 213 attachmentCount--; 214 } 215 216 Vector<Attachment> attachments(attachmentCount); 217 AttachmentResourceGuard<Vector<Attachment>, Vector<Attachment>::iterator> attachementDisposer(attachments); 218 RefPtr<WebKit::SharedMemory> oolMessageBody; 219 220 size_t fdIndex = 0; 221 for (size_t i = 0; i < attachmentCount; ++i) { 222 int fd = -1; 223 switch (attachmentInfo[i].getType()) { 224 case Attachment::MappedMemoryType: 225 if (!attachmentInfo[i].isNull()) 226 fd = m_fileDescriptors[fdIndex++]; 227 attachments[attachmentCount - i - 1] = Attachment(fd, attachmentInfo[i].getSize()); 228 break; 229 case Attachment::SocketType: 230 if (!attachmentInfo[i].isNull()) 231 fd = m_fileDescriptors[fdIndex++]; 232 attachments[attachmentCount - i - 1] = Attachment(fd); 233 break; 234 case Attachment::Uninitialized: 235 attachments[attachmentCount - i - 1] = Attachment(); 236 default: 237 break; 238 } 239 } 240 241 if (messageInfo.isMessageBodyIsOutOfLine()) { 242 ASSERT(messageInfo.bodySize()); 243 244 if (attachmentInfo[attachmentCount].isNull()) { 245 ASSERT_NOT_REACHED(); 246 return false; 247 } 248 249 WebKit::SharedMemory::Handle handle; 250 handle.adoptFromAttachment(m_fileDescriptors[attachmentFileDescriptorCount - 1], attachmentInfo[attachmentCount].getSize()); 251 252 oolMessageBody = WebKit::SharedMemory::create(handle, WebKit::SharedMemory::ReadOnly); 253 if (!oolMessageBody) { 254 ASSERT_NOT_REACHED(); 255 return false; 256 } 257 } 258 259 ASSERT(attachments.size() == (messageInfo.isMessageBodyIsOutOfLine() ? messageInfo.attachmentCount() - 1 : messageInfo.attachmentCount())); 260 261 uint8_t* messageBody = messageData; 262 if (messageInfo.isMessageBodyIsOutOfLine()) 263 messageBody = reinterpret_cast<uint8_t*>(oolMessageBody->data()); 264 265 auto decoder = std::make_unique<MessageDecoder>(DataReference(messageBody, messageInfo.bodySize()), WTF::move(attachments)); 266 267 processIncomingMessage(WTF::move(decoder)); 268 269 if (m_readBufferSize > messageLength) { 270 memmove(m_readBuffer.data(), m_readBuffer.data() + messageLength, m_readBufferSize - messageLength); 271 m_readBufferSize -= messageLength; 272 } else 273 m_readBufferSize = 0; 274 275 if (attachmentFileDescriptorCount) { 276 if (m_fileDescriptorsSize > attachmentFileDescriptorCount) { 277 size_t fileDescriptorsLength = attachmentFileDescriptorCount * sizeof(int); 278 memmove(m_fileDescriptors.data(), m_fileDescriptors.data() + fileDescriptorsLength, m_fileDescriptorsSize - fileDescriptorsLength); 279 m_fileDescriptorsSize -= fileDescriptorsLength; 280 } else 281 m_fileDescriptorsSize = 0; 282 } 283 284 285 return true; 286} 287 288static ssize_t readBytesFromSocket(int socketDescriptor, uint8_t* buffer, int count, int* fileDescriptors, size_t* fileDescriptorsCount) 289{ 290 struct msghdr message; 291 memset(&message, 0, sizeof(message)); 292 293 struct iovec iov[1]; 294 memset(&iov, 0, sizeof(iov)); 295 296 message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentMaxAmount); 297 auto attachmentDescriptorBuffer = std::make_unique<char[]>(message.msg_controllen); 298 memset(attachmentDescriptorBuffer.get(), 0, message.msg_controllen); 299 message.msg_control = attachmentDescriptorBuffer.get(); 300 301 iov[0].iov_base = buffer; 302 iov[0].iov_len = count; 303 304 message.msg_iov = iov; 305 message.msg_iovlen = 1; 306 307 while (true) { 308 ssize_t bytesRead = recvmsg(socketDescriptor, &message, 0); 309 310 if (bytesRead < 0) { 311 if (errno == EINTR) 312 continue; 313 314 return -1; 315 } 316 317 bool found = false; 318 struct cmsghdr* controlMessage; 319 for (controlMessage = CMSG_FIRSTHDR(&message); controlMessage; controlMessage = CMSG_NXTHDR(&message, controlMessage)) { 320 if (controlMessage->cmsg_level == SOL_SOCKET && controlMessage->cmsg_type == SCM_RIGHTS) { 321 *fileDescriptorsCount = (controlMessage->cmsg_len - CMSG_LEN(0)) / sizeof(int); 322 memcpy(fileDescriptors, CMSG_DATA(controlMessage), sizeof(int) * *fileDescriptorsCount); 323 324 for (size_t i = 0; i < *fileDescriptorsCount; ++i) { 325 while (fcntl(fileDescriptors[i], F_SETFD, FD_CLOEXEC) == -1) { 326 if (errno != EINTR) { 327 ASSERT_NOT_REACHED(); 328 break; 329 } 330 } 331 } 332 333 found = true; 334 break; 335 } 336 } 337 338 if (!found) 339 *fileDescriptorsCount = 0; 340 341 return bytesRead; 342 } 343 344 return -1; 345} 346 347void Connection::readyReadHandler() 348{ 349 while (true) { 350 size_t fileDescriptorsCount = 0; 351 size_t bytesToRead = m_readBuffer.size() - m_readBufferSize; 352 ssize_t bytesRead = readBytesFromSocket(m_socketDescriptor, m_readBuffer.data() + m_readBufferSize, bytesToRead, 353 m_fileDescriptors.data() + m_fileDescriptorsSize, &fileDescriptorsCount); 354 355 if (bytesRead < 0) { 356 // EINTR was already handled by readBytesFromSocket. 357 if (errno == EAGAIN || errno == EWOULDBLOCK) 358 return; 359 360 WTFLogAlways("Error receiving IPC message on socket %d in process %d: %s", m_socketDescriptor, getpid(), strerror(errno)); 361 connectionDidClose(); 362 return; 363 } 364 365 m_readBufferSize += bytesRead; 366 m_fileDescriptorsSize += fileDescriptorsCount; 367 368 if (!bytesRead) { 369 connectionDidClose(); 370 return; 371 } 372 373 // Process messages from data received. 374 while (true) { 375 if (!processMessage()) 376 break; 377 } 378 } 379} 380 381bool Connection::open() 382{ 383 int flags = fcntl(m_socketDescriptor, F_GETFL, 0); 384 while (fcntl(m_socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) { 385 if (errno != EINTR) { 386 ASSERT_NOT_REACHED(); 387 return false; 388 } 389 } 390 391 m_isConnected = true; 392#if PLATFORM(GTK) 393 RefPtr<Connection> protector(this); 394 m_connectionQueue->registerSocketEventHandler(m_socketDescriptor, 395 [=] { 396 protector->readyReadHandler(); 397 }, 398 [=] { 399 protector->connectionDidClose(); 400 }); 401#elif PLATFORM(EFL) 402 RefPtr<Connection> protector(this); 403 m_connectionQueue->registerSocketEventHandler(m_socketDescriptor, 404 [protector] { 405 protector->readyReadHandler(); 406 }); 407#endif 408 409 // Schedule a call to readyReadHandler. Data may have arrived before installation of the signal 410 // handler. 411 m_connectionQueue->dispatch(WTF::bind(&Connection::readyReadHandler, this)); 412 413 return true; 414} 415 416bool Connection::platformCanSendOutgoingMessages() const 417{ 418 return m_isConnected; 419} 420 421bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder) 422{ 423 COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline); 424 425 Vector<Attachment> attachments = encoder->releaseAttachments(); 426 AttachmentResourceGuard<Vector<Attachment>, Vector<Attachment>::iterator> attachementDisposer(attachments); 427 428 if (attachments.size() > (attachmentMaxAmount - 1)) { 429 ASSERT_NOT_REACHED(); 430 return false; 431 } 432 433 MessageInfo messageInfo(encoder->bufferSize(), attachments.size()); 434 size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(AttachmentInfo)) + encoder->bufferSize(); 435 if (messageSizeWithBodyInline > messageMaxSize && encoder->bufferSize()) { 436 RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::create(encoder->bufferSize()); 437 if (!oolMessageBody) 438 return false; 439 440 WebKit::SharedMemory::Handle handle; 441 if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::ReadOnly)) 442 return false; 443 444 messageInfo.setMessageBodyIsOutOfLine(); 445 446 memcpy(oolMessageBody->data(), encoder->buffer(), encoder->bufferSize()); 447 448 attachments.append(handle.releaseToAttachment()); 449 } 450 451 struct msghdr message; 452 memset(&message, 0, sizeof(message)); 453 454 struct iovec iov[3]; 455 memset(&iov, 0, sizeof(iov)); 456 457 message.msg_iov = iov; 458 int iovLength = 1; 459 460 iov[0].iov_base = reinterpret_cast<void*>(&messageInfo); 461 iov[0].iov_len = sizeof(messageInfo); 462 463 auto attachmentInfo = std::make_unique<AttachmentInfo[]>(attachments.size()); 464 465 size_t attachmentFDBufferLength = 0; 466 if (!attachments.isEmpty()) { 467 for (size_t i = 0; i < attachments.size(); ++i) { 468 if (attachments[i].fileDescriptor() != -1) 469 attachmentFDBufferLength++; 470 } 471 } 472 auto attachmentFDBuffer = std::make_unique<char[]>(CMSG_SPACE(sizeof(int) * attachmentFDBufferLength)); 473 474 if (!attachments.isEmpty()) { 475 int* fdPtr = 0; 476 477 if (attachmentFDBufferLength) { 478 message.msg_control = attachmentFDBuffer.get(); 479 message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentFDBufferLength); 480 memset(message.msg_control, 0, message.msg_controllen); 481 482 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message); 483 cmsg->cmsg_level = SOL_SOCKET; 484 cmsg->cmsg_type = SCM_RIGHTS; 485 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * attachmentFDBufferLength); 486 487 fdPtr = reinterpret_cast<int*>(CMSG_DATA(cmsg)); 488 } 489 490 int fdIndex = 0; 491 for (size_t i = 0; i < attachments.size(); ++i) { 492 attachmentInfo[i].setType(attachments[i].type()); 493 494 switch (attachments[i].type()) { 495 case Attachment::MappedMemoryType: 496 attachmentInfo[i].setSize(attachments[i].size()); 497 // Fall trhough, set file descriptor or null. 498 case Attachment::SocketType: 499 if (attachments[i].fileDescriptor() != -1) { 500 ASSERT(fdPtr); 501 fdPtr[fdIndex++] = attachments[i].fileDescriptor(); 502 } else 503 attachmentInfo[i].setNull(); 504 break; 505 case Attachment::Uninitialized: 506 default: 507 break; 508 } 509 } 510 511 iov[iovLength].iov_base = attachmentInfo.get(); 512 iov[iovLength].iov_len = sizeof(AttachmentInfo) * attachments.size(); 513 ++iovLength; 514 } 515 516 if (!messageInfo.isMessageBodyIsOutOfLine() && encoder->bufferSize()) { 517 iov[iovLength].iov_base = reinterpret_cast<void*>(encoder->buffer()); 518 iov[iovLength].iov_len = encoder->bufferSize(); 519 ++iovLength; 520 } 521 522 message.msg_iovlen = iovLength; 523 524 int bytesSent = 0; 525 while ((bytesSent = sendmsg(m_socketDescriptor, &message, 0)) == -1) { 526 if (errno == EINTR) 527 continue; 528 if (errno == EAGAIN || errno == EWOULDBLOCK) { 529 struct pollfd pollfd; 530 531 pollfd.fd = m_socketDescriptor; 532 pollfd.events = POLLOUT; 533 pollfd.revents = 0; 534 poll(&pollfd, 1, -1); 535 continue; 536 } 537 538 WTFLogAlways("Error sending IPC message: %s", strerror(errno)); 539 return false; 540 } 541 return true; 542} 543 544Connection::SocketPair Connection::createPlatformConnection(unsigned options) 545{ 546 int sockets[2]; 547 RELEASE_ASSERT(socketpair(AF_UNIX, SOCKET_TYPE, 0, sockets) != -1); 548 549 if (options & SetCloexecOnServer) { 550 // Don't expose the child socket to the parent process. 551 while (fcntl(sockets[1], F_SETFD, FD_CLOEXEC) == -1) 552 RELEASE_ASSERT(errno != EINTR); 553 } 554 555 if (options & SetCloexecOnClient) { 556 // Don't expose the parent socket to potential future children. 557 while (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1) 558 RELEASE_ASSERT(errno != EINTR); 559 } 560 561 SocketPair socketPair = { sockets[0], sockets[1] }; 562 return socketPair; 563} 564 565void Connection::willSendSyncMessage(unsigned flags) 566{ 567 UNUSED_PARAM(flags); 568} 569 570void Connection::didReceiveSyncReply(unsigned flags) 571{ 572 UNUSED_PARAM(flags); 573} 574 575} // namespace IPC 576