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