|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "nsIServiceManager.h" |
|
8 #include "UDPSocketParent.h" |
|
9 #include "nsComponentManagerUtils.h" |
|
10 #include "nsIUDPSocket.h" |
|
11 #include "nsINetAddr.h" |
|
12 #include "mozilla/unused.h" |
|
13 #include "mozilla/net/DNS.h" |
|
14 |
|
15 namespace mozilla { |
|
16 namespace dom { |
|
17 |
|
18 static void |
|
19 FireInternalError(mozilla::net::PUDPSocketParent *aActor, uint32_t aLineNo) |
|
20 { |
|
21 mozilla::unused << |
|
22 aActor->SendCallback(NS_LITERAL_CSTRING("onerror"), |
|
23 UDPError(NS_LITERAL_CSTRING("Internal error"), |
|
24 NS_LITERAL_CSTRING(__FILE__), aLineNo, 0), |
|
25 NS_LITERAL_CSTRING("connecting")); |
|
26 } |
|
27 |
|
28 static nsresult |
|
29 ConvertNetAddrToString(mozilla::net::NetAddr &netAddr, nsACString *address, uint16_t *port) |
|
30 { |
|
31 NS_ENSURE_ARG_POINTER(address); |
|
32 NS_ENSURE_ARG_POINTER(port); |
|
33 |
|
34 *port = 0; |
|
35 uint32_t bufSize = 0; |
|
36 |
|
37 switch(netAddr.raw.family) { |
|
38 case AF_INET: |
|
39 *port = PR_ntohs(netAddr.inet.port); |
|
40 bufSize = mozilla::net::kIPv4CStrBufSize; |
|
41 break; |
|
42 case AF_INET6: |
|
43 *port = PR_ntohs(netAddr.inet6.port); |
|
44 bufSize = mozilla::net::kIPv6CStrBufSize; |
|
45 break; |
|
46 default: |
|
47 //impossible |
|
48 MOZ_ASSERT(false, "Unexpected address family"); |
|
49 return NS_ERROR_INVALID_ARG; |
|
50 } |
|
51 |
|
52 address->SetCapacity(bufSize); |
|
53 NetAddrToString(&netAddr, address->BeginWriting(), bufSize); |
|
54 address->SetLength(strlen(address->BeginReading())); |
|
55 |
|
56 return NS_OK; |
|
57 } |
|
58 |
|
59 NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener) |
|
60 |
|
61 UDPSocketParent::~UDPSocketParent() |
|
62 { |
|
63 } |
|
64 |
|
65 // PUDPSocketParent methods |
|
66 |
|
67 bool |
|
68 UDPSocketParent::Init(const nsCString &aHost, const uint16_t aPort) |
|
69 { |
|
70 nsresult rv; |
|
71 NS_ASSERTION(mFilter, "No packet filter"); |
|
72 |
|
73 nsCOMPtr<nsIUDPSocket> sock = |
|
74 do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); |
|
75 if (NS_FAILED(rv)) { |
|
76 FireInternalError(this, __LINE__); |
|
77 return true; |
|
78 } |
|
79 |
|
80 if (aHost.IsEmpty()) { |
|
81 rv = sock->Init(aPort, false); |
|
82 } else { |
|
83 PRNetAddr prAddr; |
|
84 PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr); |
|
85 PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr); |
|
86 if (status != PR_SUCCESS) { |
|
87 FireInternalError(this, __LINE__); |
|
88 return true; |
|
89 } |
|
90 |
|
91 mozilla::net::NetAddr addr; |
|
92 PRNetAddrToNetAddr(&prAddr, &addr); |
|
93 rv = sock->InitWithAddress(&addr); |
|
94 } |
|
95 |
|
96 if (NS_FAILED(rv)) { |
|
97 FireInternalError(this, __LINE__); |
|
98 return true; |
|
99 } |
|
100 |
|
101 mSocket = sock; |
|
102 |
|
103 net::NetAddr localAddr; |
|
104 mSocket->GetAddress(&localAddr); |
|
105 |
|
106 uint16_t port; |
|
107 nsCString addr; |
|
108 rv = ConvertNetAddrToString(localAddr, &addr, &port); |
|
109 |
|
110 if (NS_FAILED(rv)) { |
|
111 FireInternalError(this, __LINE__); |
|
112 return true; |
|
113 } |
|
114 |
|
115 // register listener |
|
116 mSocket->AsyncListen(this); |
|
117 mozilla::unused << |
|
118 PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onopen"), |
|
119 UDPAddressInfo(addr, port), |
|
120 NS_LITERAL_CSTRING("connected")); |
|
121 |
|
122 return true; |
|
123 } |
|
124 |
|
125 bool |
|
126 UDPSocketParent::RecvData(const InfallibleTArray<uint8_t> &aData, |
|
127 const nsCString& aRemoteAddress, |
|
128 const uint16_t& aPort) |
|
129 { |
|
130 NS_ENSURE_TRUE(mSocket, true); |
|
131 NS_ASSERTION(mFilter, "No packet filter"); |
|
132 // TODO, Bug 933102, filter packets that are sent with hostname. |
|
133 // Until then we simply throw away packets that are sent to a hostname. |
|
134 return true; |
|
135 |
|
136 #if 0 |
|
137 // Enable this once we have filtering working with hostname delivery. |
|
138 uint32_t count; |
|
139 nsresult rv = mSocket->Send(aRemoteAddress, |
|
140 aPort, aData.Elements(), |
|
141 aData.Length(), &count); |
|
142 mozilla::unused << |
|
143 PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"), |
|
144 UDPSendResult(rv), |
|
145 NS_LITERAL_CSTRING("connected")); |
|
146 NS_ENSURE_SUCCESS(rv, true); |
|
147 NS_ENSURE_TRUE(count > 0, true); |
|
148 return true; |
|
149 #endif |
|
150 } |
|
151 |
|
152 bool |
|
153 UDPSocketParent::RecvDataWithAddress(const InfallibleTArray<uint8_t>& aData, |
|
154 const mozilla::net::NetAddr& aAddr) |
|
155 { |
|
156 NS_ENSURE_TRUE(mSocket, true); |
|
157 NS_ASSERTION(mFilter, "No packet filter"); |
|
158 |
|
159 uint32_t count; |
|
160 nsresult rv; |
|
161 bool allowed; |
|
162 rv = mFilter->FilterPacket(&aAddr, aData.Elements(), |
|
163 aData.Length(), nsIUDPSocketFilter::SF_OUTGOING, |
|
164 &allowed); |
|
165 // Sending unallowed data, kill content. |
|
166 NS_ENSURE_SUCCESS(rv, false); |
|
167 NS_ENSURE_TRUE(allowed, false); |
|
168 |
|
169 rv = mSocket->SendWithAddress(&aAddr, aData.Elements(), |
|
170 aData.Length(), &count); |
|
171 mozilla::unused << |
|
172 PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"), |
|
173 UDPSendResult(rv), |
|
174 NS_LITERAL_CSTRING("connected")); |
|
175 NS_ENSURE_SUCCESS(rv, true); |
|
176 NS_ENSURE_TRUE(count > 0, true); |
|
177 return true; |
|
178 } |
|
179 |
|
180 bool |
|
181 UDPSocketParent::RecvClose() |
|
182 { |
|
183 NS_ENSURE_TRUE(mSocket, true); |
|
184 nsresult rv = mSocket->Close(); |
|
185 mSocket = nullptr; |
|
186 NS_ENSURE_SUCCESS(rv, true); |
|
187 return true; |
|
188 } |
|
189 |
|
190 bool |
|
191 UDPSocketParent::RecvRequestDelete() |
|
192 { |
|
193 mozilla::unused << Send__delete__(this); |
|
194 return true; |
|
195 } |
|
196 |
|
197 void |
|
198 UDPSocketParent::ActorDestroy(ActorDestroyReason why) |
|
199 { |
|
200 MOZ_ASSERT(mIPCOpen); |
|
201 mIPCOpen = false; |
|
202 if (mSocket) { |
|
203 mSocket->Close(); |
|
204 } |
|
205 mSocket = nullptr; |
|
206 } |
|
207 |
|
208 // nsIUDPSocketListener |
|
209 |
|
210 NS_IMETHODIMP |
|
211 UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage) |
|
212 { |
|
213 // receiving packet from remote host, forward the message content to child process |
|
214 if (!mIPCOpen) { |
|
215 return NS_OK; |
|
216 } |
|
217 NS_ASSERTION(mFilter, "No packet filter"); |
|
218 |
|
219 uint16_t port; |
|
220 nsCString ip; |
|
221 nsCOMPtr<nsINetAddr> fromAddr; |
|
222 aMessage->GetFromAddr(getter_AddRefs(fromAddr)); |
|
223 fromAddr->GetPort(&port); |
|
224 fromAddr->GetAddress(ip); |
|
225 |
|
226 nsCString data; |
|
227 aMessage->GetData(data); |
|
228 |
|
229 const char* buffer = data.get(); |
|
230 uint32_t len = data.Length(); |
|
231 |
|
232 bool allowed; |
|
233 mozilla::net::NetAddr addr; |
|
234 fromAddr->GetNetAddr(&addr); |
|
235 nsresult rv = mFilter->FilterPacket(&addr, |
|
236 (const uint8_t*)buffer, len, |
|
237 nsIUDPSocketFilter::SF_INCOMING, |
|
238 &allowed); |
|
239 // Receiving unallowed data, drop. |
|
240 NS_ENSURE_SUCCESS(rv, NS_OK); |
|
241 NS_ENSURE_TRUE(allowed, NS_OK); |
|
242 |
|
243 FallibleTArray<uint8_t> fallibleArray; |
|
244 if (!fallibleArray.InsertElementsAt(0, buffer, len)) { |
|
245 FireInternalError(this, __LINE__); |
|
246 return NS_ERROR_OUT_OF_MEMORY; |
|
247 } |
|
248 InfallibleTArray<uint8_t> infallibleArray; |
|
249 infallibleArray.SwapElements(fallibleArray); |
|
250 |
|
251 // compose callback |
|
252 mozilla::unused << |
|
253 PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("ondata"), |
|
254 UDPMessage(ip, port, infallibleArray), |
|
255 NS_LITERAL_CSTRING("connected")); |
|
256 |
|
257 return NS_OK; |
|
258 } |
|
259 |
|
260 NS_IMETHODIMP |
|
261 UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus) |
|
262 { |
|
263 // underlying socket is dead, send state update to child process |
|
264 if (mIPCOpen) { |
|
265 mozilla::unused << |
|
266 PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onclose"), |
|
267 mozilla::void_t(), |
|
268 NS_LITERAL_CSTRING("closed")); |
|
269 } |
|
270 return NS_OK; |
|
271 } |
|
272 |
|
273 } // namespace dom |
|
274 } // namespace mozilla |