1/*
2 * Copyright (C) 2018 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 "MessagePortChannelRegistry.h"
28
29#include "Logging.h"
30#include <wtf/CompletionHandler.h>
31#include <wtf/MainThread.h>
32
33namespace WebCore {
34
35MessagePortChannelRegistry::MessagePortChannelRegistry(MessagePortChannelProvider& provider)
36 : m_provider(provider)
37{
38}
39
40MessagePortChannelRegistry::~MessagePortChannelRegistry()
41{
42 ASSERT(m_openChannels.isEmpty());
43}
44
45void MessagePortChannelRegistry::didCreateMessagePortChannel(const MessagePortIdentifier& port1, const MessagePortIdentifier& port2)
46{
47 LOG(MessagePorts, "Registry: Creating MessagePortChannel %p linking %s and %s", this, port1.logString().utf8().data(), port2.logString().utf8().data());
48 ASSERT(isMainThread());
49
50 MessagePortChannel::create(*this, port1, port2);
51}
52
53void MessagePortChannelRegistry::messagePortChannelCreated(MessagePortChannel& channel)
54{
55 ASSERT(isMainThread());
56
57 auto result = m_openChannels.ensure(channel.port1(), [channel = &channel] {
58 return channel;
59 });
60 ASSERT(result.isNewEntry);
61
62 result = m_openChannels.ensure(channel.port2(), [channel = &channel] {
63 return channel;
64 });
65 ASSERT(result.isNewEntry);
66}
67
68void MessagePortChannelRegistry::messagePortChannelDestroyed(MessagePortChannel& channel)
69{
70 ASSERT(isMainThread());
71
72 ASSERT(m_openChannels.get(channel.port1()) == &channel);
73 ASSERT(m_openChannels.get(channel.port2()) == &channel);
74
75 m_openChannels.remove(channel.port1());
76 m_openChannels.remove(channel.port2());
77
78 LOG(MessagePorts, "Registry: After removing channel %s there are %u channels left in the registry:", channel.logString().utf8().data(), m_openChannels.size());
79}
80
81void MessagePortChannelRegistry::didEntangleLocalToRemote(const MessagePortIdentifier& local, const MessagePortIdentifier& remote, ProcessIdentifier process)
82{
83 ASSERT(isMainThread());
84
85 // The channel might be gone if the remote side was closed.
86 auto* channel = m_openChannels.get(local);
87 if (!channel)
88 return;
89
90 ASSERT_UNUSED(remote, channel->includesPort(remote));
91
92 channel->entanglePortWithProcess(local, process);
93}
94
95void MessagePortChannelRegistry::didDisentangleMessagePort(const MessagePortIdentifier& port)
96{
97 ASSERT(isMainThread());
98
99 // The channel might be gone if the remote side was closed.
100 auto* channel = m_openChannels.get(port);
101 if (!channel)
102 return;
103
104 channel->disentanglePort(port);
105}
106
107void MessagePortChannelRegistry::didCloseMessagePort(const MessagePortIdentifier& port)
108{
109 ASSERT(isMainThread());
110
111 LOG(MessagePorts, "Registry: MessagePort %s closed in registry", port.logString().utf8().data());
112
113 auto* channel = m_openChannels.get(port);
114 if (!channel)
115 return;
116
117#ifndef NDEBUG
118 if (channel && channel->hasAnyMessagesPendingOrInFlight())
119 LOG(MessagePorts, "Registry: (Note) The channel closed for port %s had messages pending or in flight", port.logString().utf8().data());
120#endif
121
122 channel->closePort(port);
123
124 // FIXME: When making message ports be multi-process, this should probably push a notification
125 // to the remaining port to tell it this port closed.
126}
127
128bool MessagePortChannelRegistry::didPostMessageToRemote(MessageWithMessagePorts&& message, const MessagePortIdentifier& remoteTarget)
129{
130 ASSERT(isMainThread());
131
132 LOG(MessagePorts, "Registry: Posting message to MessagePort %s in registry", remoteTarget.logString().utf8().data());
133
134 // The channel might be gone if the remote side was closed.
135 auto* channel = m_openChannels.get(remoteTarget);
136 if (!channel) {
137 LOG(MessagePorts, "Registry: Could not find MessagePortChannel for port %s; It was probably closed. Message will be dropped.", remoteTarget.logString().utf8().data());
138 return false;
139 }
140
141 return channel->postMessageToRemote(WTFMove(message), remoteTarget);
142}
143
144void MessagePortChannelRegistry::takeAllMessagesForPort(const MessagePortIdentifier& port, Function<void(Vector<MessageWithMessagePorts>&&, Function<void()>&&)>&& callback)
145{
146 ASSERT(isMainThread());
147
148 LOG(MessagePorts, "Registry: Taking all messages for MessagePort %s", port.logString().utf8().data());
149
150 // The channel might be gone if the remote side was closed.
151 auto* channel = m_openChannels.get(port);
152 if (!channel) {
153 callback({ }, [] { });
154 return;
155 }
156
157 channel->takeAllMessagesForPort(port, WTFMove(callback));
158}
159
160void MessagePortChannelRegistry::checkRemotePortForActivity(const MessagePortIdentifier& remoteTarget, CompletionHandler<void(MessagePortChannelProvider::HasActivity)>&& callback)
161{
162 ASSERT(isMainThread());
163
164 // The channel might be gone if the remote side was closed.
165 auto* channel = m_openChannels.get(remoteTarget);
166 if (!channel) {
167 callback(MessagePortChannelProvider::HasActivity::No);
168 return;
169 }
170
171 channel->checkRemotePortForActivity(remoteTarget, WTFMove(callback));
172}
173
174MessagePortChannel* MessagePortChannelRegistry::existingChannelContainingPort(const MessagePortIdentifier& port)
175{
176 ASSERT(isMainThread());
177
178 return m_openChannels.get(port);
179}
180
181} // namespace WebCore
182