[GLIB] Remove support for GSocket main loop sources from GMainLoopSource
[WebKit-https.git] / Source / WebKit2 / Platform / IPC / unix / ConnectionUnix.cpp
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/StdLibExtras.h>
40 #include <wtf/UniStdExtras.h>
41
42 #if PLATFORM(GTK)
43 #include <gio/gio.h>
44 #endif
45
46 #if defined(SOCK_SEQPACKET) && !PLATFORM(GTK)
47 #define SOCKET_TYPE SOCK_SEQPACKET
48 #else
49 #if PLATFORM(GTK)
50 #define SOCKET_TYPE SOCK_STREAM
51 #else
52 #define SOCKET_TYPE SOCK_DGRAM
53 #endif
54 #endif // SOCK_SEQPACKET
55
56 namespace IPC {
57
58 static const size_t messageMaxSize = 4096;
59 static const size_t attachmentMaxAmount = 255;
60
61 enum {
62     MessageBodyIsOutOfLine = 1U << 31
63 };
64
65 class MessageInfo {
66 public:
67     MessageInfo() { }
68
69     MessageInfo(size_t bodySize, size_t initialAttachmentCount)
70         : m_bodySize(bodySize)
71         , m_attachmentCount(initialAttachmentCount)
72         , m_isMessageBodyOutOfLine(false)
73     {
74     }
75
76     void setMessageBodyIsOutOfLine()
77     {
78         ASSERT(!isMessageBodyIsOutOfLine());
79
80         m_isMessageBodyOutOfLine = true;
81         m_attachmentCount++;
82     }
83
84     bool isMessageBodyIsOutOfLine() const { return m_isMessageBodyOutOfLine; }
85
86     size_t bodySize() const { return m_bodySize; }
87
88     size_t attachmentCount() const { return m_attachmentCount; }
89
90 private:
91     size_t m_bodySize;
92     size_t m_attachmentCount;
93     bool m_isMessageBodyOutOfLine;
94 };
95
96 class AttachmentInfo {
97     WTF_MAKE_FAST_ALLOCATED;
98 public:
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
124 private:
125     Attachment::Type m_type;
126     size_t m_size;
127     bool m_isNull;
128 };
129
130 void 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
139 void 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)
151     m_socketMonitor.stop();
152 #elif PLATFORM(EFL)
153     m_connectionQueue->unregisterSocketEventHandler(m_socketDescriptor);
154 #endif
155
156     m_socketDescriptor = -1;
157     m_isConnected = false;
158 }
159
160 bool Connection::processMessage()
161 {
162     if (m_readBufferSize < sizeof(MessageInfo))
163         return false;
164
165     uint8_t* messageData = m_readBuffer.data();
166     MessageInfo messageInfo;
167     memcpy(&messageInfo, messageData, sizeof(messageInfo));
168     messageData += sizeof(messageInfo);
169
170     size_t messageLength = sizeof(MessageInfo) + messageInfo.attachmentCount() * sizeof(AttachmentInfo) + (messageInfo.isMessageBodyIsOutOfLine() ? 0 : messageInfo.bodySize());
171     if (m_readBufferSize < messageLength)
172         return false;
173
174     size_t attachmentFileDescriptorCount = 0;
175     size_t attachmentCount = messageInfo.attachmentCount();
176     std::unique_ptr<AttachmentInfo[]> attachmentInfo;
177
178     if (attachmentCount) {
179         attachmentInfo = std::make_unique<AttachmentInfo[]>(attachmentCount);
180         memcpy(attachmentInfo.get(), messageData, sizeof(AttachmentInfo) * attachmentCount);
181         messageData += sizeof(AttachmentInfo) * attachmentCount;
182
183         for (size_t i = 0; i < attachmentCount; ++i) {
184             switch (attachmentInfo[i].getType()) {
185             case Attachment::MappedMemoryType:
186             case Attachment::SocketType:
187                 if (!attachmentInfo[i].isNull())
188                     attachmentFileDescriptorCount++;
189                 break;
190             case Attachment::Uninitialized:
191             default:
192                 break;
193             }
194         }
195
196         if (messageInfo.isMessageBodyIsOutOfLine())
197             attachmentCount--;
198     }
199
200     Vector<Attachment> attachments(attachmentCount);
201     RefPtr<WebKit::SharedMemory> oolMessageBody;
202
203     size_t fdIndex = 0;
204     for (size_t i = 0; i < attachmentCount; ++i) {
205         int fd = -1;
206         switch (attachmentInfo[i].getType()) {
207         case Attachment::MappedMemoryType:
208             if (!attachmentInfo[i].isNull())
209                 fd = m_fileDescriptors[fdIndex++];
210             attachments[attachmentCount - i - 1] = Attachment(fd, attachmentInfo[i].getSize());
211             break;
212         case Attachment::SocketType:
213             if (!attachmentInfo[i].isNull())
214                 fd = m_fileDescriptors[fdIndex++];
215             attachments[attachmentCount - i - 1] = Attachment(fd);
216             break;
217         case Attachment::Uninitialized:
218             attachments[attachmentCount - i - 1] = Attachment();
219         default:
220             break;
221         }
222     }
223
224     if (messageInfo.isMessageBodyIsOutOfLine()) {
225         ASSERT(messageInfo.bodySize());
226
227         if (attachmentInfo[attachmentCount].isNull()) {
228             ASSERT_NOT_REACHED();
229             return false;
230         }
231
232         WebKit::SharedMemory::Handle handle;
233         handle.adoptAttachment(IPC::Attachment(m_fileDescriptors[attachmentFileDescriptorCount - 1], attachmentInfo[attachmentCount].getSize()));
234
235         oolMessageBody = WebKit::SharedMemory::map(handle, WebKit::SharedMemory::Protection::ReadOnly);
236         if (!oolMessageBody) {
237             ASSERT_NOT_REACHED();
238             return false;
239         }
240     }
241
242     ASSERT(attachments.size() == (messageInfo.isMessageBodyIsOutOfLine() ? messageInfo.attachmentCount() - 1 : messageInfo.attachmentCount()));
243
244     uint8_t* messageBody = messageData;
245     if (messageInfo.isMessageBodyIsOutOfLine())
246         messageBody = reinterpret_cast<uint8_t*>(oolMessageBody->data());
247
248     auto decoder = std::make_unique<MessageDecoder>(DataReference(messageBody, messageInfo.bodySize()), WTF::move(attachments));
249
250     processIncomingMessage(WTF::move(decoder));
251
252     if (m_readBufferSize > messageLength) {
253         memmove(m_readBuffer.data(), m_readBuffer.data() + messageLength, m_readBufferSize - messageLength);
254         m_readBufferSize -= messageLength;
255     } else
256         m_readBufferSize = 0;
257
258     if (attachmentFileDescriptorCount) {
259         if (m_fileDescriptorsSize > attachmentFileDescriptorCount) {
260             size_t fileDescriptorsLength = attachmentFileDescriptorCount * sizeof(int);
261             memmove(m_fileDescriptors.data(), m_fileDescriptors.data() + fileDescriptorsLength, m_fileDescriptorsSize - fileDescriptorsLength);
262             m_fileDescriptorsSize -= fileDescriptorsLength;
263         } else
264             m_fileDescriptorsSize = 0;
265     }
266
267
268     return true;
269 }
270
271 static ssize_t readBytesFromSocket(int socketDescriptor, uint8_t* buffer, int count, int* fileDescriptors, size_t* fileDescriptorsCount)
272 {
273     struct msghdr message;
274     memset(&message, 0, sizeof(message));
275
276     struct iovec iov[1];
277     memset(&iov, 0, sizeof(iov));
278
279     message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentMaxAmount);
280     MallocPtr<char> attachmentDescriptorBuffer = MallocPtr<char>::malloc(sizeof(char) * message.msg_controllen);
281     memset(attachmentDescriptorBuffer.get(), 0, sizeof(char) * message.msg_controllen);
282     message.msg_control = attachmentDescriptorBuffer.get();
283
284     iov[0].iov_base = buffer;
285     iov[0].iov_len = count;
286
287     message.msg_iov = iov;
288     message.msg_iovlen = 1;
289
290     while (true) {
291         ssize_t bytesRead = recvmsg(socketDescriptor, &message, 0);
292
293         if (bytesRead < 0) {
294             if (errno == EINTR)
295                 continue;
296
297             return -1;
298         }
299
300         bool found = false;
301         struct cmsghdr* controlMessage;
302         for (controlMessage = CMSG_FIRSTHDR(&message); controlMessage; controlMessage = CMSG_NXTHDR(&message, controlMessage)) {
303             if (controlMessage->cmsg_level == SOL_SOCKET && controlMessage->cmsg_type == SCM_RIGHTS) {
304                 *fileDescriptorsCount = (controlMessage->cmsg_len - CMSG_LEN(0)) / sizeof(int);
305                 memcpy(fileDescriptors, CMSG_DATA(controlMessage), sizeof(int) * *fileDescriptorsCount);
306
307                 for (size_t i = 0; i < *fileDescriptorsCount; ++i) {
308                     while (fcntl(fileDescriptors[i], F_SETFD, FD_CLOEXEC) == -1) {
309                         if (errno != EINTR) {
310                             ASSERT_NOT_REACHED();
311                             break;
312                         }
313                     }
314                 }
315
316                 found = true;
317                 break;
318             }
319         }
320
321         if (!found)
322             *fileDescriptorsCount = 0;
323
324         return bytesRead;
325     }
326
327     return -1;
328 }
329
330 void Connection::readyReadHandler()
331 {
332     while (true) {
333         size_t fileDescriptorsCount = 0;
334         size_t bytesToRead = m_readBuffer.size() - m_readBufferSize;
335         ssize_t bytesRead = readBytesFromSocket(m_socketDescriptor, m_readBuffer.data() + m_readBufferSize, bytesToRead,
336                                                 m_fileDescriptors.data() + m_fileDescriptorsSize, &fileDescriptorsCount);
337
338         if (bytesRead < 0) {
339             // EINTR was already handled by readBytesFromSocket.
340             if (errno == EAGAIN || errno == EWOULDBLOCK)
341                 return;
342
343             if (m_isConnected) {
344                 WTFLogAlways("Error receiving IPC message on socket %d in process %d: %s", m_socketDescriptor, getpid(), strerror(errno));
345                 connectionDidClose();
346             }
347             return;
348         }
349
350         m_readBufferSize += bytesRead;
351         m_fileDescriptorsSize += fileDescriptorsCount;
352
353         if (!bytesRead) {
354             connectionDidClose();
355             return;
356         }
357
358         // Process messages from data received.
359         while (true) {
360             if (!processMessage())
361                 break;
362         }
363     }
364 }
365
366 bool Connection::open()
367 {
368     int flags = fcntl(m_socketDescriptor, F_GETFL, 0);
369     while (fcntl(m_socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) {
370         if (errno != EINTR) {
371             ASSERT_NOT_REACHED();
372             return false;
373         }
374     }
375
376     RefPtr<Connection> protectedThis(this);
377     m_isConnected = true;
378 #if PLATFORM(GTK)
379     GRefPtr<GSocket> socket = adoptGRef(g_socket_new_from_fd(m_socketDescriptor, nullptr));
380     m_socketMonitor.start(socket.get(), G_IO_IN, m_connectionQueue->runLoop(), [protectedThis] (GIOCondition condition) -> gboolean {
381         if (condition & G_IO_HUP || condition & G_IO_ERR || condition & G_IO_NVAL) {
382             protectedThis->connectionDidClose();
383             return G_SOURCE_REMOVE;
384         }
385
386         if (condition & G_IO_IN) {
387             protectedThis->readyReadHandler();
388             return G_SOURCE_CONTINUE;
389         }
390
391         ASSERT_NOT_REACHED();
392         return G_SOURCE_REMOVE;
393     });
394 #elif PLATFORM(EFL)
395     m_connectionQueue->registerSocketEventHandler(m_socketDescriptor,
396         [protectedThis] {
397             protectedThis->readyReadHandler();
398         });
399 #endif
400
401     // Schedule a call to readyReadHandler. Data may have arrived before installation of the signal handler.
402     m_connectionQueue->dispatch([protectedThis] {
403         protectedThis->readyReadHandler();
404     });
405
406     return true;
407 }
408
409 bool Connection::platformCanSendOutgoingMessages() const
410 {
411     return m_isConnected;
412 }
413
414 bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder)
415 {
416     COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline);
417
418     Vector<Attachment> attachments = encoder->releaseAttachments();
419     if (attachments.size() > (attachmentMaxAmount - 1)) {
420         ASSERT_NOT_REACHED();
421         return false;
422     }
423
424     MessageInfo messageInfo(encoder->bufferSize(), attachments.size());
425     size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(AttachmentInfo)) + encoder->bufferSize();
426     if (messageSizeWithBodyInline > messageMaxSize && encoder->bufferSize()) {
427         RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::allocate(encoder->bufferSize());
428         if (!oolMessageBody)
429             return false;
430
431         WebKit::SharedMemory::Handle handle;
432         if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::Protection::ReadOnly))
433             return false;
434
435         messageInfo.setMessageBodyIsOutOfLine();
436
437         memcpy(oolMessageBody->data(), encoder->buffer(), encoder->bufferSize());
438
439         attachments.append(handle.releaseAttachment());
440     }
441
442     struct msghdr message;
443     memset(&message, 0, sizeof(message));
444
445     struct iovec iov[3];
446     memset(&iov, 0, sizeof(iov));
447
448     message.msg_iov = iov;
449     int iovLength = 1;
450
451     iov[0].iov_base = reinterpret_cast<void*>(&messageInfo);
452     iov[0].iov_len = sizeof(messageInfo);
453
454     std::unique_ptr<AttachmentInfo[]> attachmentInfo;
455     MallocPtr<char> attachmentFDBuffer;
456
457     if (!attachments.isEmpty()) {
458         int* fdPtr = 0;
459
460         size_t attachmentFDBufferLength = std::count_if(attachments.begin(), attachments.end(),
461             [](const Attachment& attachment) {
462                 return attachment.fileDescriptor() != -1;
463             });
464
465         if (attachmentFDBufferLength) {
466             attachmentFDBuffer = MallocPtr<char>::malloc(sizeof(char) * CMSG_SPACE(sizeof(int) * attachmentFDBufferLength));
467
468             message.msg_control = attachmentFDBuffer.get();
469             message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentFDBufferLength);
470             memset(message.msg_control, 0, message.msg_controllen);
471
472             struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message);
473             cmsg->cmsg_level = SOL_SOCKET;
474             cmsg->cmsg_type = SCM_RIGHTS;
475             cmsg->cmsg_len = CMSG_LEN(sizeof(int) * attachmentFDBufferLength);
476
477             fdPtr = reinterpret_cast<int*>(CMSG_DATA(cmsg));
478         }
479
480         attachmentInfo = std::make_unique<AttachmentInfo[]>(attachments.size());
481         int fdIndex = 0;
482         for (size_t i = 0; i < attachments.size(); ++i) {
483             attachmentInfo[i].setType(attachments[i].type());
484
485             switch (attachments[i].type()) {
486             case Attachment::MappedMemoryType:
487                 attachmentInfo[i].setSize(attachments[i].size());
488                 // Fall trhough, set file descriptor or null.
489             case Attachment::SocketType:
490                 if (attachments[i].fileDescriptor() != -1) {
491                     ASSERT(fdPtr);
492                     fdPtr[fdIndex++] = attachments[i].fileDescriptor();
493                 } else
494                     attachmentInfo[i].setNull();
495                 break;
496             case Attachment::Uninitialized:
497             default:
498                 break;
499             }
500         }
501
502         iov[iovLength].iov_base = attachmentInfo.get();
503         iov[iovLength].iov_len = sizeof(AttachmentInfo) * attachments.size();
504         ++iovLength;
505     }
506
507     if (!messageInfo.isMessageBodyIsOutOfLine() && encoder->bufferSize()) {
508         iov[iovLength].iov_base = reinterpret_cast<void*>(encoder->buffer());
509         iov[iovLength].iov_len = encoder->bufferSize();
510         ++iovLength;
511     }
512
513     message.msg_iovlen = iovLength;
514
515     while (sendmsg(m_socketDescriptor, &message, 0) == -1) {
516         if (errno == EINTR)
517             continue;
518         if (errno == EAGAIN || errno == EWOULDBLOCK) {
519             struct pollfd pollfd;
520
521             pollfd.fd = m_socketDescriptor;
522             pollfd.events = POLLOUT;
523             pollfd.revents = 0;
524             poll(&pollfd, 1, -1);
525             continue;
526         }
527
528         if (m_isConnected)
529             WTFLogAlways("Error sending IPC message: %s", strerror(errno));
530         return false;
531     }
532     return true;
533 }
534
535 Connection::SocketPair Connection::createPlatformConnection(unsigned options)
536 {
537     int sockets[2];
538     RELEASE_ASSERT(socketpair(AF_UNIX, SOCKET_TYPE, 0, sockets) != -1);
539
540     if (options & SetCloexecOnServer) {
541         // Don't expose the child socket to the parent process.
542         while (fcntl(sockets[1], F_SETFD, FD_CLOEXEC)  == -1)
543             RELEASE_ASSERT(errno != EINTR);
544     }
545
546     if (options & SetCloexecOnClient) {
547         // Don't expose the parent socket to potential future children.
548         while (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1)
549             RELEASE_ASSERT(errno != EINTR);
550     }
551
552     SocketPair socketPair = { sockets[0], sockets[1] };
553     return socketPair;
554 }
555     
556 void Connection::willSendSyncMessage(unsigned flags)
557 {
558     UNUSED_PARAM(flags);
559 }
560     
561 void Connection::didReceiveSyncReply(unsigned flags)
562 {
563     UNUSED_PARAM(flags);    
564 }
565
566 } // namespace IPC