[EFL][WK2] Add RunLoopEfl and WorkQueueEfl
[WebKit-https.git] / Source / WebKit2 / Platform / CoreIPC / 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 "ArgumentEncoder.h"
32 #include "SharedMemory.h"
33 #include <sys/socket.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <wtf/Assertions.h>
38 #include <wtf/Functional.h>
39 #include <wtf/OwnArrayPtr.h>
40
41 #if PLATFORM(QT)
42 #include <QSocketNotifier>
43 #include <QWeakPointer>
44 #elif PLATFORM(GTK)
45 #include <glib.h>
46 #endif
47
48 using namespace std;
49
50 namespace CoreIPC {
51
52 static const size_t messageMaxSize = 4096;
53 static const size_t attachmentMaxAmount = 255;
54
55 enum {
56     MessageBodyIsOOL = 1U << 31
57 };
58
59 class MessageInfo {
60 public:
61     MessageInfo() { }
62
63     MessageInfo(MessageID messageID, size_t bodySize, size_t initialAttachmentCount)
64         : m_messageID(messageID.toInt())
65         , m_bodySize(bodySize)
66         , m_attachmentCount(initialAttachmentCount)
67     {
68         ASSERT(!(m_messageID & MessageBodyIsOOL));
69     }
70
71     void setMessageBodyOOL()
72     {
73         ASSERT(!isMessageBodyOOL());
74
75         m_messageID |= MessageBodyIsOOL;
76         m_attachmentCount++;
77     }
78
79     bool isMessageBodyOOL() const { return m_messageID & MessageBodyIsOOL; }
80
81     size_t bodySize() const { return m_bodySize; }
82
83     MessageID messageID() const { return MessageID::fromInt(m_messageID & ~MessageBodyIsOOL); }
84
85     size_t attachmentCount() const { return m_attachmentCount; }
86
87 private:
88     uint32_t m_messageID;
89     size_t m_bodySize;
90     size_t m_attachmentCount;
91 };
92
93 class AttachmentInfo {
94 public:
95     AttachmentInfo()
96         : m_type(Attachment::Uninitialized)
97         , m_size(0)
98         , m_isNull(false)
99     {
100     }
101
102     void setType(Attachment::Type type) { m_type = type; }
103     Attachment::Type getType() { return m_type; }
104     void setSize(size_t size)
105     {
106         ASSERT(m_type == Attachment::MappedMemoryType);
107         m_size = size;
108     }
109
110     size_t getSize()
111     {
112         ASSERT(m_type == Attachment::MappedMemoryType);
113         return m_size;
114     }
115
116     // The attachment is not null unless explicitly set.
117     void setNull() { m_isNull = true; }
118     bool isNull() { return m_isNull; }
119
120 private:
121     Attachment::Type m_type;
122     size_t m_size;
123     bool m_isNull;
124 };
125
126 void Connection::platformInitialize(Identifier identifier)
127 {
128     m_socketDescriptor = identifier;
129     m_readBuffer.resize(messageMaxSize);
130     m_readBufferSize = 0;
131     m_fileDescriptors.resize(attachmentMaxAmount);
132     m_fileDescriptorsSize = 0;
133
134 #if PLATFORM(QT)
135     m_socketNotifier = 0;
136 #endif
137 }
138
139 void Connection::platformInvalidate()
140 {
141     if (m_socketDescriptor != -1)
142         while (close(m_socketDescriptor) == -1 && errno == EINTR) { }
143
144     if (!m_isConnected)
145         return;
146
147 #if PLATFORM(GTK)
148     m_connectionQueue.unregisterEventSourceHandler(m_socketDescriptor);
149 #endif
150
151 #if PLATFORM(QT)
152     delete m_socketNotifier;
153     m_socketNotifier = 0;
154 #endif
155
156 #if PLATFORM(EFL)
157     m_connectionQueue.unregisterSocketEventHandler(m_socketDescriptor);
158 #endif
159
160     m_socketDescriptor = -1;
161     m_isConnected = false;
162 }
163
164 #if PLATFORM(QT)
165 class SocketNotifierResourceGuard {
166 public:
167     SocketNotifierResourceGuard(QSocketNotifier* socketNotifier)
168         : m_socketNotifier(socketNotifier)
169     {
170         m_socketNotifier.data()->setEnabled(false);
171     }
172
173     ~SocketNotifierResourceGuard()
174     {
175         if (m_socketNotifier)
176             m_socketNotifier.data()->setEnabled(true);
177     }
178
179 private:
180     QWeakPointer<QSocketNotifier> const m_socketNotifier;
181 };
182 #endif
183
184 template<class T, class iterator>
185 class AttachmentResourceGuard {
186 public:
187     AttachmentResourceGuard(T& attachments)
188         : m_attachments(attachments)
189     {
190     }
191     ~AttachmentResourceGuard()
192     {
193         iterator end = m_attachments.end();
194         for (iterator i = m_attachments.begin(); i != end; ++i)
195             i->dispose();
196     }
197 private:
198     T& m_attachments;
199 };
200
201 bool Connection::processMessage()
202 {
203     if (m_readBufferSize < sizeof(MessageInfo))
204         return false;
205
206     uint8_t* messageData = m_readBuffer.data();
207     MessageInfo messageInfo;
208     memcpy(&messageInfo, messageData, sizeof(messageInfo));
209     messageData += sizeof(messageInfo);
210
211     size_t messageLength = sizeof(MessageInfo) + messageInfo.attachmentCount() * sizeof(AttachmentInfo) + (messageInfo.isMessageBodyOOL() ? 0 : messageInfo.bodySize());
212     if (m_readBufferSize < messageLength)
213         return false;
214
215     Deque<Attachment> attachments;
216     AttachmentResourceGuard<Deque<Attachment>, Deque<Attachment>::iterator> attachementDisposer(attachments);
217     RefPtr<WebKit::SharedMemory> oolMessageBody;
218
219     size_t attachmentFileDescriptorCount = 0;
220     size_t attachmentCount = messageInfo.attachmentCount();
221     if (attachmentCount) {
222         OwnArrayPtr<AttachmentInfo> attachmentInfo = adoptArrayPtr(new AttachmentInfo[attachmentCount]);
223         memcpy(attachmentInfo.get(), messageData, sizeof(AttachmentInfo) * attachmentCount);
224         messageData += sizeof(AttachmentInfo) * attachmentCount;
225
226         for (size_t i = 0; i < attachmentCount; ++i) {
227             switch (attachmentInfo[i].getType()) {
228             case Attachment::MappedMemoryType:
229             case Attachment::SocketType:
230                 if (!attachmentInfo[i].isNull())
231                     attachmentFileDescriptorCount++;
232             case Attachment::Uninitialized:
233             default:
234                 break;
235             }
236         }
237
238         if (messageInfo.isMessageBodyOOL())
239             attachmentCount--;
240
241         size_t fdIndex = 0;
242         for (size_t i = 0; i < attachmentCount; ++i) {
243             int fd = -1;
244             switch (attachmentInfo[i].getType()) {
245             case Attachment::MappedMemoryType:
246                 if (!attachmentInfo[i].isNull())
247                     fd = m_fileDescriptors[fdIndex++];
248                 attachments.append(Attachment(fd, attachmentInfo[i].getSize()));
249                 break;
250             case Attachment::SocketType:
251                 if (!attachmentInfo[i].isNull())
252                     fd = m_fileDescriptors[fdIndex++];
253                 attachments.append(Attachment(fd));
254                 break;
255             case Attachment::Uninitialized:
256                 attachments.append(Attachment());
257             default:
258                 break;
259             }
260         }
261
262         if (messageInfo.isMessageBodyOOL()) {
263             ASSERT(messageInfo.bodySize());
264
265             if (attachmentInfo[attachmentCount].isNull()) {
266                 ASSERT_NOT_REACHED();
267                 return false;
268             }
269
270             WebKit::SharedMemory::Handle handle;
271             handle.adoptFromAttachment(m_fileDescriptors[attachmentFileDescriptorCount - 1], attachmentInfo[attachmentCount].getSize());
272
273             oolMessageBody = WebKit::SharedMemory::create(handle, WebKit::SharedMemory::ReadOnly);
274             if (!oolMessageBody) {
275                 ASSERT_NOT_REACHED();
276                 return false;
277             }
278         }
279     }
280
281     ASSERT(attachments.size() == messageInfo.isMessageBodyOOL() ? messageInfo.attachmentCount() - 1 : messageInfo.attachmentCount());
282
283     uint8_t* messageBody = messageData;
284     if (messageInfo.isMessageBodyOOL())
285         messageBody = reinterpret_cast<uint8_t*>(oolMessageBody->data());
286
287     ArgumentDecoder* argumentDecoder;
288     if (attachments.isEmpty())
289         argumentDecoder = new ArgumentDecoder(messageBody, messageInfo.bodySize());
290     else
291         argumentDecoder = new ArgumentDecoder(messageBody, messageInfo.bodySize(), attachments);
292
293     processIncomingMessage(messageInfo.messageID(), adoptPtr(argumentDecoder));
294
295     if (m_readBufferSize > messageLength) {
296         memmove(m_readBuffer.data(), m_readBuffer.data() + messageLength, m_readBufferSize - messageLength);
297         m_readBufferSize -= messageLength;
298     } else
299         m_readBufferSize = 0;
300
301     if (attachmentFileDescriptorCount) {
302         if (m_fileDescriptorsSize > attachmentFileDescriptorCount) {
303             size_t fileDescriptorsLength = attachmentFileDescriptorCount * sizeof(int);
304             memmove(m_fileDescriptors.data(), m_fileDescriptors.data() + fileDescriptorsLength, m_fileDescriptorsSize - fileDescriptorsLength);
305             m_fileDescriptorsSize -= fileDescriptorsLength;
306         } else
307             m_fileDescriptorsSize = 0;
308     }
309
310
311     return true;
312 }
313
314 static ssize_t readBytesFromSocket(int socketDescriptor, uint8_t* buffer, int count, int* fileDescriptors, size_t* fileDescriptorsCount)
315 {
316     struct msghdr message;
317     memset(&message, 0, sizeof(message));
318
319     struct iovec iov[1];
320     memset(&iov, 0, sizeof(iov));
321
322     message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentMaxAmount);
323     OwnArrayPtr<char> attachmentDescriptorBuffer = adoptArrayPtr(new char[message.msg_controllen]);
324     memset(attachmentDescriptorBuffer.get(), 0, message.msg_controllen);
325     message.msg_control = attachmentDescriptorBuffer.get();
326
327     iov[0].iov_base = buffer;
328     iov[0].iov_len = count;
329
330     message.msg_iov = iov;
331     message.msg_iovlen = 1;
332
333     while (true) {
334         ssize_t bytesRead = recvmsg(socketDescriptor, &message, 0);
335
336         if (bytesRead < 0) {
337             if (errno == EINTR)
338                 continue;
339
340             return -1;
341         }
342
343         bool found = false;
344         struct cmsghdr* controlMessage;
345         for (controlMessage = CMSG_FIRSTHDR(&message); controlMessage; controlMessage = CMSG_NXTHDR(&message, controlMessage)) {
346             if (controlMessage->cmsg_level == SOL_SOCKET && controlMessage->cmsg_type == SCM_RIGHTS) {
347                 *fileDescriptorsCount = (controlMessage->cmsg_len - CMSG_LEN(0)) / sizeof(int);
348                 memcpy(fileDescriptors, CMSG_DATA(controlMessage), sizeof(int) * *fileDescriptorsCount);
349
350                 for (size_t i = 0; i < *fileDescriptorsCount; ++i) {
351                     while (fcntl(fileDescriptors[i], F_SETFL, FD_CLOEXEC) == -1) {
352                         if (errno != EINTR) {
353                             ASSERT_NOT_REACHED();
354                             break;
355                         }
356                     }
357                 }
358
359                 found = true;
360                 break;
361             }
362         }
363
364         if (!found)
365             *fileDescriptorsCount = 0;
366
367         return bytesRead;
368     }
369
370     return -1;
371 }
372
373 void Connection::readyReadHandler()
374 {
375 #if PLATFORM(QT)
376     SocketNotifierResourceGuard socketNotifierEnabler(m_socketNotifier);
377 #endif
378
379     while (true) {
380         size_t fileDescriptorsCount = 0;
381         size_t bytesToRead = m_readBuffer.size() - m_readBufferSize;
382         ssize_t bytesRead = readBytesFromSocket(m_socketDescriptor, m_readBuffer.data() + m_readBufferSize, bytesToRead,
383                                                 m_fileDescriptors.data() + m_fileDescriptorsSize, &fileDescriptorsCount);
384
385         if (bytesRead < 0) {
386             // EINTR was already handled by readBytesFromSocket.
387             if (errno == EAGAIN || errno == EWOULDBLOCK)
388                 return;
389
390             // FIXME: Handle other errors here?
391             return;
392         }
393
394         m_readBufferSize += bytesRead;
395         m_fileDescriptorsSize += fileDescriptorsCount;
396
397         if (!bytesRead) {
398             connectionDidClose();
399             return;
400         }
401
402         // Process messages from data received.
403         while (true) {
404             if (!processMessage())
405                 break;
406         }
407     }
408 }
409
410 bool Connection::open()
411 {
412 #if PLATFORM(QT)
413     ASSERT(!m_socketNotifier);
414 #endif
415
416     int flags = fcntl(m_socketDescriptor, F_GETFL, 0);
417     while (fcntl(m_socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) {
418         if (errno != EINTR) {
419             ASSERT_NOT_REACHED();
420             return false;
421         }
422     }
423
424     m_isConnected = true;
425 #if PLATFORM(QT)
426     m_socketNotifier = m_connectionQueue.registerSocketEventHandler(m_socketDescriptor, QSocketNotifier::Read, bind(&Connection::readyReadHandler, this));
427 #elif PLATFORM(GTK)
428     m_connectionQueue.registerEventSourceHandler(m_socketDescriptor, (G_IO_HUP | G_IO_ERR), bind(&Connection::connectionDidClose, this));
429     m_connectionQueue.registerEventSourceHandler(m_socketDescriptor, G_IO_IN, bind(&Connection::readyReadHandler, this));
430 #elif PLATFORM(EFL)
431     m_connectionQueue.registerSocketEventHandler(m_socketDescriptor, bind(&Connection::readyReadHandler, this));
432 #endif
433
434     // Schedule a call to readyReadHandler. Data may have arrived before installation of the signal
435     // handler.
436     m_connectionQueue.dispatch(bind(&Connection::readyReadHandler, this));
437
438     return true;
439 }
440
441 bool Connection::platformCanSendOutgoingMessages() const
442 {
443     return m_isConnected;
444 }
445
446 bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments)
447 {
448 #if PLATFORM(QT)
449     ASSERT(m_socketNotifier);
450 #endif
451
452     COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline);
453
454     Vector<Attachment> attachments = arguments->releaseAttachments();
455     AttachmentResourceGuard<Vector<Attachment>, Vector<Attachment>::iterator> attachementDisposer(attachments);
456
457     if (attachments.size() > (attachmentMaxAmount - 1)) {
458         ASSERT_NOT_REACHED();
459         return false;
460     }
461
462     MessageInfo messageInfo(messageID, arguments->bufferSize(), attachments.size());
463     size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(AttachmentInfo)) + arguments->bufferSize();
464     if (messageSizeWithBodyInline > messageMaxSize && arguments->bufferSize()) {
465         RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::create(arguments->bufferSize());
466         if (!oolMessageBody)
467             return false;
468
469         WebKit::SharedMemory::Handle handle;
470         if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::ReadOnly))
471             return false;
472
473         messageInfo.setMessageBodyOOL();
474
475         memcpy(oolMessageBody->data(), arguments->buffer(), arguments->bufferSize());
476
477         attachments.append(handle.releaseToAttachment());
478     }
479
480     struct msghdr message;
481     memset(&message, 0, sizeof(message));
482
483     struct iovec iov[3];
484     memset(&iov, 0, sizeof(iov));
485
486     message.msg_iov = iov;
487     int iovLength = 1;
488
489     iov[0].iov_base = reinterpret_cast<void*>(&messageInfo);
490     iov[0].iov_len = sizeof(messageInfo);
491
492     OwnArrayPtr<AttachmentInfo> attachmentInfo = adoptArrayPtr(new AttachmentInfo[attachments.size()]);
493
494     size_t attachmentFDBufferLength = 0;
495     if (!attachments.isEmpty()) {
496         for (size_t i = 0; i < attachments.size(); ++i) {
497             if (attachments[i].fileDescriptor() != -1)
498                 attachmentFDBufferLength++;
499         }
500     }
501     OwnArrayPtr<char> attachmentFDBuffer = adoptArrayPtr(new char[CMSG_SPACE(sizeof(int) * attachmentFDBufferLength)]);
502
503     if (!attachments.isEmpty()) {
504         int* fdPtr = 0;
505
506         if (attachmentFDBufferLength) {
507             message.msg_control = attachmentFDBuffer.get();
508             message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentFDBufferLength);
509             memset(message.msg_control, 0, message.msg_controllen);
510
511             struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message);
512             cmsg->cmsg_level = SOL_SOCKET;
513             cmsg->cmsg_type = SCM_RIGHTS;
514             cmsg->cmsg_len = CMSG_LEN(sizeof(int) * attachmentFDBufferLength);
515
516             fdPtr = reinterpret_cast<int*>(CMSG_DATA(cmsg));
517         }
518
519         int fdIndex = 0;
520         for (size_t i = 0; i < attachments.size(); ++i) {
521             attachmentInfo[i].setType(attachments[i].type());
522
523             switch (attachments[i].type()) {
524             case Attachment::MappedMemoryType:
525                 attachmentInfo[i].setSize(attachments[i].size());
526                 // Fall trhough, set file descriptor or null.
527             case Attachment::SocketType:
528                 if (attachments[i].fileDescriptor() != -1) {
529                     ASSERT(fdPtr);
530                     fdPtr[fdIndex++] = attachments[i].fileDescriptor();
531                 } else
532                     attachmentInfo[i].setNull();
533                 break;
534             case Attachment::Uninitialized:
535             default:
536                 break;
537             }
538         }
539
540         iov[iovLength].iov_base = attachmentInfo.get();
541         iov[iovLength].iov_len = sizeof(AttachmentInfo) * attachments.size();
542         ++iovLength;
543     }
544
545     if (!messageInfo.isMessageBodyOOL() && arguments->bufferSize()) {
546         iov[iovLength].iov_base = reinterpret_cast<void*>(arguments->buffer());
547         iov[iovLength].iov_len = arguments->bufferSize();
548         ++iovLength;
549     }
550
551     message.msg_iovlen = iovLength;
552
553     int bytesSent = 0;
554     while ((bytesSent = sendmsg(m_socketDescriptor, &message, 0)) == -1) {
555         if (errno != EINTR)
556             return false;
557     }
558     return true;
559 }
560
561 #if PLATFORM(QT)
562 void Connection::setShouldCloseConnectionOnProcessTermination(WebKit::PlatformProcessIdentifier process)
563 {
564     m_connectionQueue.dispatchOnTermination(process, bind(&Connection::connectionDidClose, this));
565 }
566 #endif
567
568 } // namespace CoreIPC