]> git.saurik.com Git - apple/javascriptcore.git/blob - inspector/remote/RemoteInspectorXPCConnection.mm
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / inspector / remote / RemoteInspectorXPCConnection.mm
1 /*
2 * Copyright (C) 2013 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #import "config.h"
27 #import "RemoteInspectorXPCConnection.h"
28
29 #if ENABLE(REMOTE_INSPECTOR)
30
31 #import <Foundation/Foundation.h>
32 #import <wtf/Assertions.h>
33 #import <wtf/Ref.h>
34
35 #if __has_include(<CoreFoundation/CFXPCBridge.h>)
36 #import <CoreFoundation/CFXPCBridge.h>
37 #else
38 extern "C" xpc_object_t _CFXPCCreateXPCMessageWithCFObject(CFTypeRef);
39 extern "C" CFTypeRef _CFXPCCreateCFObjectFromXPCMessage(xpc_object_t);
40 #endif
41
42 namespace Inspector {
43
44 // Constants private to this file for message serialization on both ends.
45 #define RemoteInspectorXPCConnectionMessageNameKey @"messageName"
46 #define RemoteInspectorXPCConnectionUserInfoKey @"userInfo"
47 #define RemoteInspectorXPCConnectionSerializedMessageKey "msgData"
48
49 RemoteInspectorXPCConnection::RemoteInspectorXPCConnection(xpc_connection_t connection, dispatch_queue_t queue, Client* client)
50 : m_connection(connection)
51 , m_queue(queue)
52 , m_client(client)
53 , m_closed(false)
54 {
55 dispatch_retain(m_queue);
56
57 xpc_retain(m_connection);
58 xpc_connection_set_target_queue(m_connection, m_queue);
59 xpc_connection_set_event_handler(m_connection, ^(xpc_object_t object) {
60 handleEvent(object);
61 });
62
63 // Balanced by deref when the xpc_connection receives XPC_ERROR_CONNECTION_INVALID.
64 ref();
65
66 xpc_connection_resume(m_connection);
67 }
68
69 RemoteInspectorXPCConnection::~RemoteInspectorXPCConnection()
70 {
71 ASSERT(!m_client);
72 ASSERT(!m_connection);
73 ASSERT(m_closed);
74 }
75
76 void RemoteInspectorXPCConnection::close()
77 {
78 std::lock_guard<std::mutex> lock(m_mutex);
79 closeFromMessage();
80 }
81
82 void RemoteInspectorXPCConnection::closeFromMessage()
83 {
84 m_closed = true;
85 m_client = nullptr;
86
87 dispatch_async(m_queue, ^{
88 std::lock_guard<std::mutex> lock(m_mutex);
89 // This will trigger one last XPC_ERROR_CONNECTION_INVALID event on the queue and deref us.
90 closeOnQueue();
91 });
92 }
93
94 void RemoteInspectorXPCConnection::closeOnQueue()
95 {
96 if (m_connection) {
97 xpc_connection_cancel(m_connection);
98 xpc_release(m_connection);
99 m_connection = NULL;
100 }
101
102 if (m_queue) {
103 dispatch_release(m_queue);
104 m_queue = NULL;
105 }
106 }
107
108 NSDictionary *RemoteInspectorXPCConnection::deserializeMessage(xpc_object_t object)
109 {
110 if (xpc_get_type(object) != XPC_TYPE_DICTIONARY)
111 return nil;
112
113 xpc_object_t xpcDictionary = xpc_dictionary_get_value(object, RemoteInspectorXPCConnectionSerializedMessageKey);
114 if (!xpcDictionary || xpc_get_type(xpcDictionary) != XPC_TYPE_DICTIONARY) {
115 std::lock_guard<std::mutex> lock(m_mutex);
116 if (m_client)
117 m_client->xpcConnectionUnhandledMessage(this, object);
118 return nil;
119 }
120
121 NSDictionary *dictionary = static_cast<NSDictionary *>(_CFXPCCreateCFObjectFromXPCMessage(xpcDictionary));
122 ASSERT_WITH_MESSAGE(dictionary, "Unable to deserialize xpc message");
123 return [dictionary autorelease];
124 }
125
126 void RemoteInspectorXPCConnection::handleEvent(xpc_object_t object)
127 {
128 if (xpc_get_type(object) == XPC_TYPE_ERROR) {
129 {
130 std::lock_guard<std::mutex> lock(m_mutex);
131 if (m_client)
132 m_client->xpcConnectionFailed(this);
133
134 m_closed = true;
135 m_client = nullptr;
136 closeOnQueue();
137 }
138
139 if (object == XPC_ERROR_CONNECTION_INVALID) {
140 // This is the last event we will ever receive from the connection.
141 // This balances the ref() in the constructor.
142 deref();
143 }
144 return;
145 }
146
147 NSDictionary *dataDictionary = deserializeMessage(object);
148 if (!dataDictionary)
149 return;
150
151 NSString *message = [dataDictionary objectForKey:RemoteInspectorXPCConnectionMessageNameKey];
152 NSDictionary *userInfo = [dataDictionary objectForKey:RemoteInspectorXPCConnectionUserInfoKey];
153 std::lock_guard<std::mutex> lock(m_mutex);
154 if (m_client)
155 m_client->xpcConnectionReceivedMessage(this, message, userInfo);
156 }
157
158 void RemoteInspectorXPCConnection::sendMessage(NSString *messageName, NSDictionary *userInfo)
159 {
160 ASSERT(!m_closed);
161 if (m_closed)
162 return;
163
164 NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObject:messageName forKey:RemoteInspectorXPCConnectionMessageNameKey];
165 if (userInfo)
166 [dictionary setObject:userInfo forKey:RemoteInspectorXPCConnectionUserInfoKey];
167
168 xpc_object_t xpcDictionary = _CFXPCCreateXPCMessageWithCFObject((CFDictionaryRef)dictionary);
169 ASSERT_WITH_MESSAGE(xpcDictionary && xpc_get_type(xpcDictionary) == XPC_TYPE_DICTIONARY, "Unable to serialize xpc message");
170 if (!xpcDictionary)
171 return;
172
173 xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
174 xpc_dictionary_set_value(msg, RemoteInspectorXPCConnectionSerializedMessageKey, xpcDictionary);
175 xpc_release(xpcDictionary);
176
177 xpc_connection_send_message(m_connection, msg);
178
179 xpc_release(msg);
180 }
181
182 } // namespace Inspector
183
184 #endif // ENABLE(REMOTE_INSPECTOR)