Simplify createDataAvailableSource
[WebKit-https.git] / Source / WebKit2 / Platform / IPC / mac / ConnectionMac.mm
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "Connection.h"
28
29 #include "DataReference.h"
30 #include "ImportanceAssertion.h"
31 #include "MachPort.h"
32 #include "MachUtilities.h"
33 #include <mach/mach_error.h>
34 #include <mach/vm_map.h>
35 #include <wtf/RunLoop.h>
36 #include <xpc/xpc.h>
37
38 #if __has_include(<xpc/private.h>)
39 #include <xpc/private.h>
40 #endif
41
42 extern "C" void xpc_connection_get_audit_token(xpc_connection_t, audit_token_t*);
43
44 namespace IPC {
45
46 static const size_t inlineMessageMaxSize = 4096;
47
48 // Message flags.
49 enum {
50     MessageBodyIsOutOfLine = 1 << 0
51 };
52     
53 void Connection::platformInvalidate()
54 {
55     if (!m_isConnected)
56         return;
57
58     m_isConnected = false;
59
60     ASSERT(m_sendPort);
61     ASSERT(m_receivePort);
62
63     // Unregister our ports.
64     dispatch_source_cancel(m_deadNameSource);
65     dispatch_release(m_deadNameSource);
66     m_deadNameSource = 0;
67     m_sendPort = MACH_PORT_NULL;
68
69     dispatch_source_cancel(m_receivePortDataAvailableSource);
70     dispatch_release(m_receivePortDataAvailableSource);
71     m_receivePortDataAvailableSource = 0;
72     m_receivePort = MACH_PORT_NULL;
73
74 #if !PLATFORM(IOS)
75     if (m_exceptionPort) {
76         dispatch_source_cancel(m_exceptionPortDataAvailableSource);
77         dispatch_release(m_exceptionPortDataAvailableSource);
78         m_exceptionPortDataAvailableSource = 0;
79         m_exceptionPort = MACH_PORT_NULL;
80     }
81 #endif
82
83     if (m_xpcConnection) {
84         xpc_release(m_xpcConnection);
85         m_xpcConnection = 0;
86     }
87 }
88
89 void Connection::platformInitialize(Identifier identifier)
90 {
91 #if !PLATFORM(IOS)
92     m_exceptionPort = MACH_PORT_NULL;
93     m_exceptionPortDataAvailableSource = nullptr;
94 #endif
95
96     if (m_isServer) {
97         m_receivePort = identifier.port;
98         m_sendPort = MACH_PORT_NULL;
99     } else {
100         m_receivePort = MACH_PORT_NULL;
101         m_sendPort = identifier.port;
102     }
103
104     m_deadNameSource = nullptr;
105     m_receivePortDataAvailableSource = nullptr;
106
107     m_xpcConnection = identifier.xpcConnection;
108     // FIXME: Instead of explicitly retaining the connection here, Identifier::xpcConnection
109     // should just be a smart pointer.
110     if (m_xpcConnection)
111         xpc_retain(m_xpcConnection);
112 }
113
114 template<typename Function>
115 static dispatch_source_t createDataAvailableSource(mach_port_t receivePort, WorkQueue& workQueue, Function&& function)
116 {
117     dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, receivePort, 0, workQueue.dispatchQueue());
118     dispatch_source_set_event_handler(source, function);
119
120     dispatch_source_set_cancel_handler(source, ^{
121         mach_port_mod_refs(mach_task_self(), receivePort, MACH_PORT_RIGHT_RECEIVE, -1);
122     });
123
124     return source;
125 }
126
127 bool Connection::open()
128 {
129     if (m_isServer) {
130         ASSERT(m_receivePort);
131         ASSERT(!m_sendPort);
132         
133     } else {
134         ASSERT(!m_receivePort);
135         ASSERT(m_sendPort);
136
137         // Create the receive port.
138         mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_receivePort);
139
140 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
141         mach_port_set_attributes(mach_task_self(), m_receivePort, MACH_PORT_IMPORTANCE_RECEIVER, (mach_port_info_t)0, 0);
142 #endif
143
144         m_isConnected = true;
145         
146         // Send the initialize message, which contains a send right for the server to use.
147         auto encoder = std::make_unique<MessageEncoder>("IPC", "InitializeConnection", 0);
148         encoder->encode(MachPort(m_receivePort, MACH_MSG_TYPE_MAKE_SEND));
149
150         sendMessage(std::move(encoder));
151
152         initializeDeadNameSource();
153     }
154
155     // Change the message queue length for the receive port.
156     setMachPortQueueLength(m_receivePort, MACH_PORT_QLIMIT_LARGE);
157
158     // Register the data available handler.
159     RefPtr<Connection> connection(this);
160     m_receivePortDataAvailableSource = createDataAvailableSource(m_receivePort, *m_connectionQueue, [connection] {
161         connection->receiveSourceEventHandler();
162     });
163
164 #if !PLATFORM(IOS)
165     // If we have an exception port, register the data available handler and send over the port to the other end.
166     if (m_exceptionPort) {
167         m_exceptionPortDataAvailableSource = createDataAvailableSource(m_exceptionPort, *m_connectionQueue, [connection] {
168             connection->exceptionSourceEventHandler();
169         });
170
171         auto encoder = std::make_unique<MessageEncoder>("IPC", "SetExceptionPort", 0);
172         encoder->encode(MachPort(m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND));
173
174         sendMessage(std::move(encoder));
175     }
176 #endif
177
178     ref();
179     dispatch_async(m_connectionQueue->dispatchQueue(), ^{
180         dispatch_resume(m_receivePortDataAvailableSource);
181
182         if (m_deadNameSource)
183             dispatch_resume(m_deadNameSource);
184 #if !PLATFORM(IOS)
185         if (m_exceptionPortDataAvailableSource)
186             dispatch_resume(m_exceptionPortDataAvailableSource);
187 #endif
188
189         deref();
190     });
191
192     return true;
193 }
194
195 static inline size_t machMessageSize(size_t bodySize, size_t numberOfPortDescriptors = 0, size_t numberOfOOLMemoryDescriptors = 0)
196 {
197     size_t size = sizeof(mach_msg_header_t) + bodySize;
198     if (numberOfPortDescriptors || numberOfOOLMemoryDescriptors) {
199         size += sizeof(mach_msg_body_t);
200         if (numberOfPortDescriptors)
201             size += (numberOfPortDescriptors * sizeof(mach_msg_port_descriptor_t));
202         if (numberOfOOLMemoryDescriptors)
203             size += (numberOfOOLMemoryDescriptors * sizeof(mach_msg_ool_descriptor_t));
204     }
205     return round_msg(size);
206 }
207
208 bool Connection::platformCanSendOutgoingMessages() const
209 {
210     return true;
211 }
212
213 bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder)
214 {
215     Vector<Attachment> attachments = encoder->releaseAttachments();
216     
217     size_t numberOfPortDescriptors = 0;
218     size_t numberOfOOLMemoryDescriptors = 0;
219     for (size_t i = 0; i < attachments.size(); ++i) {
220         Attachment::Type type = attachments[i].type();
221         if (type == Attachment::MachPortType)
222             numberOfPortDescriptors++;
223     }
224     
225     size_t messageSize = machMessageSize(encoder->bufferSize(), numberOfPortDescriptors, numberOfOOLMemoryDescriptors);
226
227     bool messageBodyIsOOL = false;
228     if (messageSize > inlineMessageMaxSize) {
229         messageBodyIsOOL = true;
230
231         numberOfOOLMemoryDescriptors++;
232         messageSize = machMessageSize(0, numberOfPortDescriptors, numberOfOOLMemoryDescriptors);
233     }
234
235     char stackBuffer[inlineMessageMaxSize];
236     char* buffer = &stackBuffer[0];
237     if (messageSize > inlineMessageMaxSize)
238         buffer = (char*)mmap(0, messageSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
239
240     bool isComplex = (numberOfPortDescriptors + numberOfOOLMemoryDescriptors > 0);
241
242     mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer);
243     header->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
244     header->msgh_size = messageSize;
245     header->msgh_remote_port = m_sendPort;
246     header->msgh_local_port = MACH_PORT_NULL;
247     header->msgh_id = 0;
248     if (messageBodyIsOOL)
249         header->msgh_id |= MessageBodyIsOutOfLine;
250
251     uint8_t* messageData;
252
253     if (isComplex) {
254         header->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
255
256         mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1);
257         body->msgh_descriptor_count = numberOfPortDescriptors + numberOfOOLMemoryDescriptors;
258         uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1);
259
260         for (size_t i = 0; i < attachments.size(); ++i) {
261             Attachment attachment = attachments[i];
262
263             mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
264             switch (attachment.type()) {
265             case Attachment::MachPortType:
266                 descriptor->port.name = attachment.port();
267                 descriptor->port.disposition = attachment.disposition();
268                 descriptor->port.type = MACH_MSG_PORT_DESCRIPTOR;            
269
270                 descriptorData += sizeof(mach_msg_port_descriptor_t);
271                 break;
272             default:
273                 ASSERT_NOT_REACHED();
274             }
275         }
276
277         if (messageBodyIsOOL) {
278             mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
279
280             descriptor->out_of_line.address = encoder->buffer();
281             descriptor->out_of_line.size = encoder->bufferSize();
282             descriptor->out_of_line.copy = MACH_MSG_VIRTUAL_COPY;
283             descriptor->out_of_line.deallocate = false;
284             descriptor->out_of_line.type = MACH_MSG_OOL_DESCRIPTOR;
285
286             descriptorData += sizeof(mach_msg_ool_descriptor_t);
287         }
288
289         messageData = descriptorData;
290     } else
291         messageData = (uint8_t*)(header + 1);
292
293     // Copy the data if it is not being sent out-of-line.
294     if (!messageBodyIsOOL)
295         memcpy(messageData, encoder->buffer(), encoder->bufferSize());
296
297     ASSERT(m_sendPort);
298
299     // Send the message.
300     kern_return_t kr = mach_msg(header, MACH_SEND_MSG, messageSize, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
301     if (kr != KERN_SUCCESS) {
302         // FIXME: What should we do here?
303     }
304
305     if (buffer != &stackBuffer[0])
306         munmap(buffer, messageSize);
307
308     return true;
309 }
310
311 void Connection::initializeDeadNameSource()
312 {
313     m_deadNameSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, m_sendPort, 0, m_connectionQueue->dispatchQueue());
314     dispatch_source_set_event_handler(m_deadNameSource, bind(&Connection::connectionDidClose, this));
315
316     mach_port_t sendPort = m_sendPort;
317     dispatch_source_set_cancel_handler(m_deadNameSource, ^{
318         // Release our send right.
319         mach_port_deallocate(mach_task_self(), sendPort);
320     });
321 }
322
323 static std::unique_ptr<MessageDecoder> createMessageDecoder(mach_msg_header_t* header)
324 {
325     if (!(header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
326         // We have a simple message.
327         uint8_t* body = reinterpret_cast<uint8_t*>(header + 1);
328         size_t bodySize = header->msgh_size - sizeof(mach_msg_header_t);
329
330         return std::make_unique<MessageDecoder>(DataReference(body, bodySize), Vector<Attachment>());
331     }
332
333     bool messageBodyIsOOL = header->msgh_id & MessageBodyIsOutOfLine;
334
335     mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1);
336     mach_msg_size_t numDescriptors = body->msgh_descriptor_count;
337     ASSERT(numDescriptors);
338
339     uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1);
340
341     // If the message body was sent out-of-line, don't treat the last descriptor
342     // as an attachment, since it is really the message body.
343     if (messageBodyIsOOL)
344         --numDescriptors;
345
346     // Build attachment list
347     Vector<Attachment> attachments(numDescriptors);
348
349     for (mach_msg_size_t i = 0; i < numDescriptors; ++i) {
350         mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
351
352         switch (descriptor->type.type) {
353         case MACH_MSG_PORT_DESCRIPTOR:
354             attachments[numDescriptors - i - 1] = Attachment(descriptor->port.name, descriptor->port.disposition);
355             descriptorData += sizeof(mach_msg_port_descriptor_t);
356             break;
357         default:
358             ASSERT(false && "Unhandled descriptor type");
359         }
360     }
361
362     if (messageBodyIsOOL) {
363         mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
364         ASSERT(descriptor->type.type == MACH_MSG_OOL_DESCRIPTOR);
365
366         uint8_t* messageBody = static_cast<uint8_t*>(descriptor->out_of_line.address);
367         size_t messageBodySize = descriptor->out_of_line.size;
368
369         auto decoder = std::make_unique<MessageDecoder>(DataReference(messageBody, messageBodySize), std::move(attachments));
370
371         vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(descriptor->out_of_line.address), descriptor->out_of_line.size);
372
373         return decoder;
374     }
375
376     uint8_t* messageBody = descriptorData;
377     size_t messageBodySize = header->msgh_size - (descriptorData - reinterpret_cast<uint8_t*>(header));
378
379     return std::make_unique<MessageDecoder>(DataReference(messageBody, messageBodySize), attachments);
380 }
381
382 // The receive buffer size should always include the maximum trailer size.
383 static const size_t receiveBufferSize = inlineMessageMaxSize + MAX_TRAILER_SIZE;
384 typedef Vector<char, receiveBufferSize> ReceiveBuffer;
385
386 static mach_msg_header_t* readFromMachPort(mach_port_t machPort, ReceiveBuffer& buffer)
387 {
388     buffer.resize(receiveBufferSize);
389
390     mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer.data());
391     kern_return_t kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL);
392     if (kr == MACH_RCV_TIMED_OUT)
393         return 0;
394
395     if (kr == MACH_RCV_TOO_LARGE) {
396         // The message was too large, resize the buffer and try again.
397         buffer.resize(header->msgh_size + MAX_TRAILER_SIZE);
398         header = reinterpret_cast<mach_msg_header_t*>(buffer.data());
399         
400         kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL);
401         ASSERT(kr != MACH_RCV_TOO_LARGE);
402     }
403
404     if (kr != MACH_MSG_SUCCESS) {
405         ASSERT_NOT_REACHED();
406         return 0;
407     }
408
409     return header;
410 }
411
412 void Connection::receiveSourceEventHandler()
413 {
414     ReceiveBuffer buffer;
415
416     mach_msg_header_t* header = readFromMachPort(m_receivePort, buffer);
417     if (!header)
418         return;
419
420     std::unique_ptr<MessageDecoder> decoder = createMessageDecoder(header);
421     ASSERT(decoder);
422
423 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
424     decoder->setImportanceAssertion(std::make_unique<ImportanceAssertion>(header));
425 #endif
426
427     if (decoder->messageReceiverName() == "IPC" && decoder->messageName() == "InitializeConnection") {
428         ASSERT(m_isServer);
429         ASSERT(!m_isConnected);
430         ASSERT(!m_sendPort);
431
432         MachPort port;
433         if (!decoder->decode(port)) {
434             // FIXME: Disconnect.
435             return;
436         }
437
438         m_sendPort = port.port();
439         
440         if (m_sendPort) {
441             initializeDeadNameSource();
442             dispatch_resume(m_deadNameSource);
443         }
444
445         m_isConnected = true;
446
447         // Send any pending outgoing messages.
448         sendOutgoingMessages();
449         
450         return;
451     }
452
453 #if !PLATFORM(IOS)
454     if (decoder->messageReceiverName() == "IPC" && decoder->messageName() == "SetExceptionPort") {
455         if (m_isServer) {
456             // Server connections aren't supposed to have their exception ports overriden. Treat this as an invalid message.
457             m_clientRunLoop.dispatch(bind(&Connection::dispatchDidReceiveInvalidMessage, this, decoder->messageReceiverName().toString(), decoder->messageName().toString()));
458             return;
459         }
460         MachPort exceptionPort;
461         if (!decoder->decode(exceptionPort))
462             return;
463
464         setMachExceptionPort(exceptionPort.port());
465         return;
466     }
467 #endif
468
469     processIncomingMessage(std::move(decoder));
470 }    
471
472 #if !PLATFORM(IOS)
473 void Connection::exceptionSourceEventHandler()
474 {
475     ReceiveBuffer buffer;
476
477     mach_msg_header_t* header = readFromMachPort(m_exceptionPort, buffer);
478     if (!header)
479         return;
480
481     // We've read the exception message. Now send it on to the real exception port.
482
483     // The remote port should have a send once right.
484     ASSERT(MACH_MSGH_BITS_REMOTE(header->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE);
485
486     // Now get the real exception port.
487     mach_port_t exceptionPort = machExceptionPort();
488
489     // First, get the complex bit from the source message.
490     mach_msg_bits_t messageBits = header->msgh_bits & MACH_MSGH_BITS_COMPLEX;
491     messageBits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
492
493     header->msgh_bits = messageBits;
494     header->msgh_local_port = header->msgh_remote_port;
495     header->msgh_remote_port = exceptionPort;
496
497     // Now send along the message.
498     kern_return_t kr = mach_msg(header, MACH_SEND_MSG, header->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
499     if (kr != KERN_SUCCESS) {
500         LOG_ERROR("Failed to send message to real exception port. %s (%x)", mach_error_string(kr), kr);
501         ASSERT_NOT_REACHED();
502     }
503
504     connectionDidClose();
505 }
506
507 void Connection::setShouldCloseConnectionOnMachExceptions()
508 {
509     ASSERT(m_exceptionPort == MACH_PORT_NULL);
510
511     if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_exceptionPort) != KERN_SUCCESS)
512         ASSERT_NOT_REACHED();
513
514     if (mach_port_insert_right(mach_task_self(), m_exceptionPort, m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)
515         ASSERT_NOT_REACHED();
516 }
517 #endif
518
519 IPC::Connection::Identifier Connection::identifier() const
520 {
521     return Identifier(m_isServer ? m_receivePort : m_sendPort, m_xpcConnection);
522 }
523     
524 bool Connection::getAuditToken(audit_token_t& auditToken)
525 {
526     if (!m_xpcConnection)
527         return false;
528     
529     xpc_connection_get_audit_token(m_xpcConnection, &auditToken);
530     return true;
531 }
532     
533 } // namespace IPC