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