Once we can send Mach messages again, make sure to send any pending outgoing messages
[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 "MachMessage.h"
32 #include "MachPort.h"
33 #include "MachUtilities.h"
34 #include <WebCore/AXObjectCache.h>
35 #include <mach/mach_error.h>
36 #include <mach/vm_map.h>
37 #include <sys/mman.h>
38 #include <wtf/RunLoop.h>
39 #include <wtf/spi/darwin/XPCSPI.h>
40
41 #if PLATFORM(IOS)
42 #include "ProcessAssertion.h"
43 #include <UIKit/UIAccessibility.h>
44
45 #if USE(APPLE_INTERNAL_SDK)
46 #include <AXRuntime/AXDefines.h>
47 #include <AXRuntime/AXNotificationConstants.h>
48 #else
49 #define kAXPidStatusChangedNotification 0
50 #endif
51
52 #endif
53
54 #if PLATFORM(MAC)
55
56 #if USE(APPLE_INTERNAL_SDK)
57 #include <HIServices/AccessibilityPriv.h>
58 #else
59 typedef enum {
60     AXSuspendStatusRunning = 0,
61     AXSuspendStatusSuspended,
62 } AXSuspendStatus;
63 #endif
64
65 extern "C" AXError _AXUIElementNotifyProcessSuspendStatus(AXSuspendStatus);
66
67 #endif // PLATFORM(MAC)
68
69 namespace IPC {
70
71 static const size_t inlineMessageMaxSize = 4096;
72
73 // Message flags.
74 enum {
75     MessageBodyIsOutOfLine = 1 << 0
76 };
77     
78 // ConnectionTerminationWatchdog does two things:
79 // 1) It sets a watchdog timer to kill the peered process.
80 // 2) On iOS, make the process runnable for the duration of the watchdog
81 //    to ensure it has a chance to terminate cleanly.
82 class ConnectionTerminationWatchdog {
83 public:
84     static void createConnectionTerminationWatchdog(OSObjectPtr<xpc_connection_t>& xpcConnection, double intervalInSeconds)
85     {
86         new ConnectionTerminationWatchdog(xpcConnection, intervalInSeconds);
87     }
88     
89 private:
90     ConnectionTerminationWatchdog(OSObjectPtr<xpc_connection_t>& xpcConnection, double intervalInSeconds)
91         : m_xpcConnection(xpcConnection)
92         , m_watchdogTimer(RunLoop::main(), this, &ConnectionTerminationWatchdog::watchdogTimerFired)
93 #if PLATFORM(IOS)
94         , m_assertion(std::make_unique<WebKit::ProcessAndUIAssertion>(xpc_connection_get_pid(m_xpcConnection.get()), WebKit::AssertionState::Background))
95 #endif
96     {
97         m_watchdogTimer.startOneShot(intervalInSeconds);
98     }
99     
100     void watchdogTimerFired()
101     {
102         xpc_connection_kill(m_xpcConnection.get(), SIGKILL);
103         delete this;
104     }
105
106     OSObjectPtr<xpc_connection_t> m_xpcConnection;
107     RunLoop::Timer<ConnectionTerminationWatchdog> m_watchdogTimer;
108 #if PLATFORM(IOS)
109     std::unique_ptr<WebKit::ProcessAndUIAssertion> m_assertion;
110 #endif
111 };
112     
113 void Connection::platformInvalidate()
114 {
115     if (!m_isConnected) {
116         if (m_sendPort) {
117             mach_port_deallocate(mach_task_self(), m_sendPort);
118             m_sendPort = MACH_PORT_NULL;
119         }
120
121         if (m_receivePort) {
122             mach_port_mod_refs(mach_task_self(), m_receivePort, MACH_PORT_RIGHT_RECEIVE, -1);
123             m_receivePort = MACH_PORT_NULL;
124         }
125
126         return;
127     }
128
129     m_pendingOutgoingMachMessage = nullptr;
130     m_isConnected = false;
131
132     ASSERT(m_sendPort);
133     ASSERT(m_receivePort);
134
135     // Unregister our ports.
136     dispatch_source_cancel(m_sendSource);
137     dispatch_release(m_sendSource);
138     m_sendSource = nullptr;
139     m_sendPort = MACH_PORT_NULL;
140
141     dispatch_source_cancel(m_receiveSource);
142     dispatch_release(m_receiveSource);
143     m_receiveSource = nullptr;
144     m_receivePort = MACH_PORT_NULL;
145
146 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000
147     if (m_exceptionPort) {
148         dispatch_source_cancel(m_exceptionPortDataAvailableSource);
149         dispatch_release(m_exceptionPortDataAvailableSource);
150         m_exceptionPortDataAvailableSource = 0;
151         m_exceptionPort = MACH_PORT_NULL;
152     }
153 #endif
154 }
155     
156 void Connection::terminateSoon(double intervalInSeconds)
157 {
158     if (m_xpcConnection)
159         ConnectionTerminationWatchdog::createConnectionTerminationWatchdog(m_xpcConnection, intervalInSeconds);
160 }
161     
162 void Connection::platformInitialize(Identifier identifier)
163 {
164 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000
165     m_exceptionPort = MACH_PORT_NULL;
166     m_exceptionPortDataAvailableSource = nullptr;
167 #endif
168
169     if (m_isServer) {
170         m_receivePort = identifier.port;
171         m_sendPort = MACH_PORT_NULL;
172     } else {
173         m_receivePort = MACH_PORT_NULL;
174         m_sendPort = identifier.port;
175     }
176
177     m_sendSource = nullptr;
178     m_receiveSource = nullptr;
179
180     m_xpcConnection = identifier.xpcConnection;
181 }
182
183 template<typename Function>
184 static dispatch_source_t createReceiveSource(mach_port_t receivePort, WorkQueue& workQueue, Function&& function)
185 {
186     dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, receivePort, 0, workQueue.dispatchQueue());
187     dispatch_source_set_event_handler(source, function);
188
189     dispatch_source_set_cancel_handler(source, ^{
190         mach_port_mod_refs(mach_task_self(), receivePort, MACH_PORT_RIGHT_RECEIVE, -1);
191     });
192
193     return source;
194 }
195
196 bool Connection::open()
197 {
198     if (m_isServer) {
199         ASSERT(m_receivePort);
200         ASSERT(!m_sendPort);
201         
202     } else {
203         ASSERT(!m_receivePort);
204         ASSERT(m_sendPort);
205
206         // Create the receive port.
207         mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_receivePort);
208
209 #if PLATFORM(MAC)
210         mach_port_set_attributes(mach_task_self(), m_receivePort, MACH_PORT_DENAP_RECEIVER, (mach_port_info_t)0, 0);
211 #endif
212
213         m_isConnected = true;
214         
215         // Send the initialize message, which contains a send right for the server to use.
216         auto encoder = std::make_unique<Encoder>("IPC", "InitializeConnection", 0);
217         encoder->encode(MachPort(m_receivePort, MACH_MSG_TYPE_MAKE_SEND));
218
219         initializeSendSource();
220
221         sendMessage(WTFMove(encoder), { });
222     }
223
224     // Change the message queue length for the receive port.
225     setMachPortQueueLength(m_receivePort, MACH_PORT_QLIMIT_LARGE);
226
227     // Register the data available handler.
228     RefPtr<Connection> connection(this);
229     m_receiveSource = createReceiveSource(m_receivePort, m_connectionQueue, [connection] {
230         connection->receiveSourceEventHandler();
231     });
232
233 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000
234     if (m_exceptionPort) {
235         m_exceptionPortDataAvailableSource = createReceiveSource(m_exceptionPort, m_connectionQueue, [connection] {
236             connection->exceptionSourceEventHandler();
237         });
238
239         auto encoder = std::make_unique<Encoder>("IPC", "SetExceptionPort", 0);
240         encoder->encode(MachPort(m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND));
241
242         sendMessage(WTFMove(encoder), { });
243     }
244 #endif
245
246     ref();
247     dispatch_async(m_connectionQueue->dispatchQueue(), ^{
248         dispatch_resume(m_receiveSource);
249
250         if (m_sendSource)
251             dispatch_resume(m_sendSource);
252 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000
253         if (m_exceptionPortDataAvailableSource)
254             dispatch_resume(m_exceptionPortDataAvailableSource);
255 #endif
256
257         deref();
258     });
259
260     return true;
261 }
262
263 bool Connection::sendMessage(std::unique_ptr<MachMessage> message)
264 {
265     ASSERT(!m_pendingOutgoingMachMessage);
266
267     // Send the message.
268     kern_return_t kr = mach_msg(message->header(), MACH_SEND_MSG | MACH_SEND_TIMEOUT | MACH_SEND_NOTIFY, message->size(), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
269     switch (kr) {
270     case MACH_MSG_SUCCESS:
271         // The kernel has already adopted the descriptors.
272         message->leakDescriptors();
273         return true;
274
275     case MACH_SEND_TIMED_OUT:
276         // We timed out, stash away the message for later.
277         m_pendingOutgoingMachMessage = WTFMove(message);
278         return false;
279
280     case MACH_SEND_INVALID_DEST:
281         // The other end has disappeared, we'll get a dead name notification which will cause us to be invalidated.
282         return false;
283
284     default:
285         CRASH();
286     }
287 }
288
289 bool Connection::platformCanSendOutgoingMessages() const
290 {
291     return !m_pendingOutgoingMachMessage;
292 }
293
294 bool Connection::sendOutgoingMessage(std::unique_ptr<Encoder> encoder)
295 {
296     ASSERT(!m_pendingOutgoingMachMessage);
297
298     Vector<Attachment> attachments = encoder->releaseAttachments();
299     
300     size_t numberOfPortDescriptors = 0;
301     size_t numberOfOOLMemoryDescriptors = 0;
302     for (size_t i = 0; i < attachments.size(); ++i) {
303         Attachment::Type type = attachments[i].type();
304         if (type == Attachment::MachPortType)
305             numberOfPortDescriptors++;
306     }
307     
308     size_t messageSize = MachMessage::messageSize(encoder->bufferSize(), numberOfPortDescriptors, numberOfOOLMemoryDescriptors);
309
310     bool messageBodyIsOOL = false;
311     if (messageSize > inlineMessageMaxSize) {
312         messageBodyIsOOL = true;
313
314         numberOfOOLMemoryDescriptors++;
315         messageSize = MachMessage::messageSize(0, numberOfPortDescriptors, numberOfOOLMemoryDescriptors);
316     }
317
318     auto message = MachMessage::create(messageSize);
319
320     bool isComplex = (numberOfPortDescriptors + numberOfOOLMemoryDescriptors) > 0;
321
322     mach_msg_header_t* header = message->header();
323     header->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
324     header->msgh_size = messageSize;
325     header->msgh_remote_port = m_sendPort;
326     header->msgh_local_port = MACH_PORT_NULL;
327     header->msgh_id = 0;
328     if (messageBodyIsOOL)
329         header->msgh_id |= MessageBodyIsOutOfLine;
330
331     uint8_t* messageData;
332
333     if (isComplex) {
334         header->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
335
336         mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1);
337         body->msgh_descriptor_count = numberOfPortDescriptors + numberOfOOLMemoryDescriptors;
338         uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1);
339
340         for (size_t i = 0; i < attachments.size(); ++i) {
341             Attachment attachment = attachments[i];
342
343             mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
344             switch (attachment.type()) {
345             case Attachment::MachPortType:
346                 descriptor->port.name = attachment.port();
347                 descriptor->port.disposition = attachment.disposition();
348                 descriptor->port.type = MACH_MSG_PORT_DESCRIPTOR;            
349
350                 descriptorData += sizeof(mach_msg_port_descriptor_t);
351                 break;
352             default:
353                 ASSERT_NOT_REACHED();
354             }
355         }
356
357         if (messageBodyIsOOL) {
358             mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
359
360             descriptor->out_of_line.address = encoder->buffer();
361             descriptor->out_of_line.size = encoder->bufferSize();
362             descriptor->out_of_line.copy = MACH_MSG_VIRTUAL_COPY;
363             descriptor->out_of_line.deallocate = false;
364             descriptor->out_of_line.type = MACH_MSG_OOL_DESCRIPTOR;
365
366             descriptorData += sizeof(mach_msg_ool_descriptor_t);
367         }
368
369         messageData = descriptorData;
370     } else
371         messageData = (uint8_t*)(header + 1);
372
373     // Copy the data if it is not being sent out-of-line.
374     if (!messageBodyIsOOL)
375         memcpy(messageData, encoder->buffer(), encoder->bufferSize());
376
377     ASSERT(m_sendPort);
378
379     return sendMessage(WTFMove(message));
380 }
381
382 void Connection::initializeSendSource()
383 {
384     m_sendSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, m_sendPort, DISPATCH_MACH_SEND_DEAD | DISPATCH_MACH_SEND_POSSIBLE, m_connectionQueue->dispatchQueue());
385
386     RefPtr<Connection> connection(this);
387     dispatch_source_set_event_handler(m_sendSource, [connection] {
388         if (!connection->m_sendSource)
389             return;
390
391         unsigned long data = dispatch_source_get_data(connection->m_sendSource);
392
393         if (data & DISPATCH_MACH_SEND_DEAD) {
394             connection->connectionDidClose();
395             return;
396         }
397
398         if (data & DISPATCH_MACH_SEND_POSSIBLE) {
399             connection->sendMessage(WTFMove(connection->m_pendingOutgoingMachMessage));
400             connection->sendOutgoingMessages();
401             return;
402         }
403     });
404
405     mach_port_t sendPort = m_sendPort;
406     dispatch_source_set_cancel_handler(m_sendSource, ^{
407         // Release our send right.
408         mach_port_deallocate(mach_task_self(), sendPort);
409     });
410 }
411
412 static std::unique_ptr<Decoder> createMessageDecoder(mach_msg_header_t* header)
413 {
414     if (!(header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
415         // We have a simple message.
416         uint8_t* body = reinterpret_cast<uint8_t*>(header + 1);
417         size_t bodySize = header->msgh_size - sizeof(mach_msg_header_t);
418
419         return std::make_unique<Decoder>(body, bodySize, nullptr, Vector<Attachment> { });
420     }
421
422     bool messageBodyIsOOL = header->msgh_id & MessageBodyIsOutOfLine;
423
424     mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1);
425     mach_msg_size_t numDescriptors = body->msgh_descriptor_count;
426     ASSERT(numDescriptors);
427
428     uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1);
429
430     // If the message body was sent out-of-line, don't treat the last descriptor
431     // as an attachment, since it is really the message body.
432     if (messageBodyIsOOL)
433         --numDescriptors;
434
435     // Build attachment list
436     Vector<Attachment> attachments(numDescriptors);
437
438     for (mach_msg_size_t i = 0; i < numDescriptors; ++i) {
439         mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
440
441         switch (descriptor->type.type) {
442         case MACH_MSG_PORT_DESCRIPTOR:
443             attachments[numDescriptors - i - 1] = Attachment(descriptor->port.name, descriptor->port.disposition);
444             descriptorData += sizeof(mach_msg_port_descriptor_t);
445             break;
446         default:
447             ASSERT(false && "Unhandled descriptor type");
448         }
449     }
450
451     if (messageBodyIsOOL) {
452         mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
453         ASSERT(descriptor->type.type == MACH_MSG_OOL_DESCRIPTOR);
454
455         uint8_t* messageBody = static_cast<uint8_t*>(descriptor->out_of_line.address);
456         size_t messageBodySize = descriptor->out_of_line.size;
457
458         auto decoder = std::make_unique<Decoder>(messageBody, messageBodySize, [](const uint8_t* buffer, size_t length) {
459             vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(buffer), length);
460         }, WTFMove(attachments));
461
462         return decoder;
463     }
464
465     uint8_t* messageBody = descriptorData;
466     size_t messageBodySize = header->msgh_size - (descriptorData - reinterpret_cast<uint8_t*>(header));
467
468     return std::make_unique<Decoder>(messageBody, messageBodySize, nullptr, attachments);
469 }
470
471 // The receive buffer size should always include the maximum trailer size.
472 static const size_t receiveBufferSize = inlineMessageMaxSize + MAX_TRAILER_SIZE;
473 typedef Vector<char, receiveBufferSize> ReceiveBuffer;
474
475 static mach_msg_header_t* readFromMachPort(mach_port_t machPort, ReceiveBuffer& buffer)
476 {
477     buffer.resize(receiveBufferSize);
478
479     mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer.data());
480     kern_return_t kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL);
481     if (kr == MACH_RCV_TIMED_OUT)
482         return 0;
483
484     if (kr == MACH_RCV_TOO_LARGE) {
485         // The message was too large, resize the buffer and try again.
486         buffer.resize(header->msgh_size + MAX_TRAILER_SIZE);
487         header = reinterpret_cast<mach_msg_header_t*>(buffer.data());
488         
489         kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL);
490         ASSERT(kr != MACH_RCV_TOO_LARGE);
491     }
492
493     if (kr != MACH_MSG_SUCCESS) {
494         ASSERT_NOT_REACHED();
495         return 0;
496     }
497
498     return header;
499 }
500
501 void Connection::receiveSourceEventHandler()
502 {
503     ReceiveBuffer buffer;
504
505     mach_msg_header_t* header = readFromMachPort(m_receivePort, buffer);
506     if (!header)
507         return;
508
509     switch (header->msgh_id) {
510     case MACH_NOTIFY_NO_SENDERS:
511         ASSERT(m_isServer);
512         if (!m_sendPort)
513             connectionDidClose();
514         return;
515
516     case MACH_NOTIFY_SEND_ONCE:
517         return;
518
519     default:
520         break;
521     }
522
523     std::unique_ptr<Decoder> decoder = createMessageDecoder(header);
524     ASSERT(decoder);
525
526 #if PLATFORM(MAC)
527     decoder->setImportanceAssertion(std::make_unique<ImportanceAssertion>(header));
528 #endif
529
530     if (decoder->messageReceiverName() == "IPC" && decoder->messageName() == "InitializeConnection") {
531         ASSERT(m_isServer);
532         ASSERT(!m_isConnected);
533         ASSERT(!m_sendPort);
534
535         MachPort port;
536         if (!decoder->decode(port)) {
537             // FIXME: Disconnect.
538             return;
539         }
540
541         m_sendPort = port.port();
542         
543         if (m_sendPort) {
544             mach_port_t previousNotificationPort;
545             mach_port_request_notification(mach_task_self(), m_receivePort, MACH_NOTIFY_NO_SENDERS, 0, MACH_PORT_NULL, MACH_MSG_TYPE_MOVE_SEND_ONCE, &previousNotificationPort);
546
547             if (previousNotificationPort != MACH_PORT_NULL)
548                 mach_port_deallocate(mach_task_self(), previousNotificationPort);
549
550             initializeSendSource();
551             dispatch_resume(m_sendSource);
552         }
553
554         m_isConnected = true;
555
556         // Send any pending outgoing messages.
557         sendOutgoingMessages();
558         
559         return;
560     }
561
562 #if !PLATFORM(IOS)
563     if (decoder->messageReceiverName() == "IPC" && decoder->messageName() == "SetExceptionPort") {
564         if (m_isServer) {
565             // Server connections aren't supposed to have their exception ports overriden. Treat this as an invalid message.
566             StringReference messageReceiverNameReference = decoder->messageReceiverName();
567             String messageReceiverName(String(messageReceiverNameReference.data(), messageReceiverNameReference.size()));
568             StringReference messageNameReference = decoder->messageName();
569             String messageName(String(messageNameReference.data(), messageNameReference.size()));
570
571             RunLoop::main().dispatch([protectedThis = makeRef(*this), messageReceiverName = WTFMove(messageReceiverName), messageName = WTFMove(messageName)]() mutable {
572                 protectedThis->dispatchDidReceiveInvalidMessage(messageReceiverName.utf8(), messageName.utf8());
573             });
574             return;
575         }
576         MachPort exceptionPort;
577         if (!decoder->decode(exceptionPort))
578             return;
579
580         setMachExceptionPort(exceptionPort.port());
581         return;
582     }
583 #endif
584
585     processIncomingMessage(WTFMove(decoder));
586 }    
587
588 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000
589 void Connection::exceptionSourceEventHandler()
590 {
591     ReceiveBuffer buffer;
592
593     mach_msg_header_t* header = readFromMachPort(m_exceptionPort, buffer);
594     if (!header)
595         return;
596
597     // We've read the exception message. Now send it on to the real exception port.
598
599     // The remote port should have a send once right.
600     ASSERT(MACH_MSGH_BITS_REMOTE(header->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE);
601
602     // Now get the real exception port.
603     mach_port_t exceptionPort = machExceptionPort();
604
605     // First, get the complex bit from the source message.
606     mach_msg_bits_t messageBits = header->msgh_bits & MACH_MSGH_BITS_COMPLEX;
607     messageBits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
608
609     header->msgh_bits = messageBits;
610     header->msgh_local_port = header->msgh_remote_port;
611     header->msgh_remote_port = exceptionPort;
612
613     // Now send along the message.
614     kern_return_t kr = mach_msg(header, MACH_SEND_MSG, header->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
615     if (kr != KERN_SUCCESS)
616         LOG_ERROR("Failed to send message to real exception port. %s (%x)", mach_error_string(kr), kr);
617
618     connectionDidClose();
619 }
620
621 void Connection::setShouldCloseConnectionOnMachExceptions()
622 {
623     ASSERT(m_exceptionPort == MACH_PORT_NULL);
624
625     if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_exceptionPort) != KERN_SUCCESS)
626         ASSERT_NOT_REACHED();
627
628     if (mach_port_insert_right(mach_task_self(), m_exceptionPort, m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)
629         ASSERT_NOT_REACHED();
630 }
631 #endif
632
633 IPC::Connection::Identifier Connection::identifier() const
634 {
635     return Identifier(m_isServer ? m_receivePort : m_sendPort, m_xpcConnection);
636 }
637
638 bool Connection::getAuditToken(audit_token_t& auditToken)
639 {
640     if (!m_xpcConnection)
641         return false;
642     
643     xpc_connection_get_audit_token(m_xpcConnection.get(), &auditToken);
644     return true;
645 }
646
647 bool Connection::kill()
648 {
649     if (m_xpcConnection) {
650         xpc_connection_kill(m_xpcConnection.get(), SIGKILL);
651         return true;
652     }
653
654     return false;
655 }
656     
657 static void AccessibilityProcessSuspendedNotification(bool suspended)
658 {
659 #if PLATFORM(MAC)
660     _AXUIElementNotifyProcessSuspendStatus(suspended ? AXSuspendStatusSuspended : AXSuspendStatusRunning);
661 #elif PLATFORM(IOS)
662     UIAccessibilityPostNotification(kAXPidStatusChangedNotification, @{ @"pid" : @(getpid()), @"suspended" : @(suspended) });
663 #else
664     UNUSED_PARAM(suspended);
665 #endif
666 }
667     
668 void Connection::willSendSyncMessage(OptionSet<SendSyncOption> sendSyncOptions)
669 {
670     if (sendSyncOptions.contains(IPC::SendSyncOption::InformPlatformProcessWillSuspend) && WebCore::AXObjectCache::accessibilityEnabled())
671         AccessibilityProcessSuspendedNotification(true);
672 }
673
674 void Connection::didReceiveSyncReply(OptionSet<SendSyncOption> sendSyncOptions)
675 {
676     if (sendSyncOptions.contains(IPC::SendSyncOption::InformPlatformProcessWillSuspend) && WebCore::AXObjectCache::accessibilityEnabled())
677         AccessibilityProcessSuspendedNotification(false);
678 }
679
680 pid_t Connection::remoteProcessID() const
681 {
682     if (!m_xpcConnection)
683         return 0;
684
685     return xpc_connection_get_pid(m_xpcConnection.get());
686 }
687     
688 } // namespace IPC