1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/network/src/UDPSocketParent.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,274 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsIServiceManager.h" 1.11 +#include "UDPSocketParent.h" 1.12 +#include "nsComponentManagerUtils.h" 1.13 +#include "nsIUDPSocket.h" 1.14 +#include "nsINetAddr.h" 1.15 +#include "mozilla/unused.h" 1.16 +#include "mozilla/net/DNS.h" 1.17 + 1.18 +namespace mozilla { 1.19 +namespace dom { 1.20 + 1.21 +static void 1.22 +FireInternalError(mozilla::net::PUDPSocketParent *aActor, uint32_t aLineNo) 1.23 +{ 1.24 + mozilla::unused << 1.25 + aActor->SendCallback(NS_LITERAL_CSTRING("onerror"), 1.26 + UDPError(NS_LITERAL_CSTRING("Internal error"), 1.27 + NS_LITERAL_CSTRING(__FILE__), aLineNo, 0), 1.28 + NS_LITERAL_CSTRING("connecting")); 1.29 +} 1.30 + 1.31 +static nsresult 1.32 +ConvertNetAddrToString(mozilla::net::NetAddr &netAddr, nsACString *address, uint16_t *port) 1.33 +{ 1.34 + NS_ENSURE_ARG_POINTER(address); 1.35 + NS_ENSURE_ARG_POINTER(port); 1.36 + 1.37 + *port = 0; 1.38 + uint32_t bufSize = 0; 1.39 + 1.40 + switch(netAddr.raw.family) { 1.41 + case AF_INET: 1.42 + *port = PR_ntohs(netAddr.inet.port); 1.43 + bufSize = mozilla::net::kIPv4CStrBufSize; 1.44 + break; 1.45 + case AF_INET6: 1.46 + *port = PR_ntohs(netAddr.inet6.port); 1.47 + bufSize = mozilla::net::kIPv6CStrBufSize; 1.48 + break; 1.49 + default: 1.50 + //impossible 1.51 + MOZ_ASSERT(false, "Unexpected address family"); 1.52 + return NS_ERROR_INVALID_ARG; 1.53 + } 1.54 + 1.55 + address->SetCapacity(bufSize); 1.56 + NetAddrToString(&netAddr, address->BeginWriting(), bufSize); 1.57 + address->SetLength(strlen(address->BeginReading())); 1.58 + 1.59 + return NS_OK; 1.60 +} 1.61 + 1.62 +NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener) 1.63 + 1.64 +UDPSocketParent::~UDPSocketParent() 1.65 +{ 1.66 +} 1.67 + 1.68 +// PUDPSocketParent methods 1.69 + 1.70 +bool 1.71 +UDPSocketParent::Init(const nsCString &aHost, const uint16_t aPort) 1.72 +{ 1.73 + nsresult rv; 1.74 + NS_ASSERTION(mFilter, "No packet filter"); 1.75 + 1.76 + nsCOMPtr<nsIUDPSocket> sock = 1.77 + do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); 1.78 + if (NS_FAILED(rv)) { 1.79 + FireInternalError(this, __LINE__); 1.80 + return true; 1.81 + } 1.82 + 1.83 + if (aHost.IsEmpty()) { 1.84 + rv = sock->Init(aPort, false); 1.85 + } else { 1.86 + PRNetAddr prAddr; 1.87 + PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr); 1.88 + PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr); 1.89 + if (status != PR_SUCCESS) { 1.90 + FireInternalError(this, __LINE__); 1.91 + return true; 1.92 + } 1.93 + 1.94 + mozilla::net::NetAddr addr; 1.95 + PRNetAddrToNetAddr(&prAddr, &addr); 1.96 + rv = sock->InitWithAddress(&addr); 1.97 + } 1.98 + 1.99 + if (NS_FAILED(rv)) { 1.100 + FireInternalError(this, __LINE__); 1.101 + return true; 1.102 + } 1.103 + 1.104 + mSocket = sock; 1.105 + 1.106 + net::NetAddr localAddr; 1.107 + mSocket->GetAddress(&localAddr); 1.108 + 1.109 + uint16_t port; 1.110 + nsCString addr; 1.111 + rv = ConvertNetAddrToString(localAddr, &addr, &port); 1.112 + 1.113 + if (NS_FAILED(rv)) { 1.114 + FireInternalError(this, __LINE__); 1.115 + return true; 1.116 + } 1.117 + 1.118 + // register listener 1.119 + mSocket->AsyncListen(this); 1.120 + mozilla::unused << 1.121 + PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onopen"), 1.122 + UDPAddressInfo(addr, port), 1.123 + NS_LITERAL_CSTRING("connected")); 1.124 + 1.125 + return true; 1.126 +} 1.127 + 1.128 +bool 1.129 +UDPSocketParent::RecvData(const InfallibleTArray<uint8_t> &aData, 1.130 + const nsCString& aRemoteAddress, 1.131 + const uint16_t& aPort) 1.132 +{ 1.133 + NS_ENSURE_TRUE(mSocket, true); 1.134 + NS_ASSERTION(mFilter, "No packet filter"); 1.135 + // TODO, Bug 933102, filter packets that are sent with hostname. 1.136 + // Until then we simply throw away packets that are sent to a hostname. 1.137 + return true; 1.138 + 1.139 +#if 0 1.140 + // Enable this once we have filtering working with hostname delivery. 1.141 + uint32_t count; 1.142 + nsresult rv = mSocket->Send(aRemoteAddress, 1.143 + aPort, aData.Elements(), 1.144 + aData.Length(), &count); 1.145 + mozilla::unused << 1.146 + PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"), 1.147 + UDPSendResult(rv), 1.148 + NS_LITERAL_CSTRING("connected")); 1.149 + NS_ENSURE_SUCCESS(rv, true); 1.150 + NS_ENSURE_TRUE(count > 0, true); 1.151 + return true; 1.152 +#endif 1.153 +} 1.154 + 1.155 +bool 1.156 +UDPSocketParent::RecvDataWithAddress(const InfallibleTArray<uint8_t>& aData, 1.157 + const mozilla::net::NetAddr& aAddr) 1.158 +{ 1.159 + NS_ENSURE_TRUE(mSocket, true); 1.160 + NS_ASSERTION(mFilter, "No packet filter"); 1.161 + 1.162 + uint32_t count; 1.163 + nsresult rv; 1.164 + bool allowed; 1.165 + rv = mFilter->FilterPacket(&aAddr, aData.Elements(), 1.166 + aData.Length(), nsIUDPSocketFilter::SF_OUTGOING, 1.167 + &allowed); 1.168 + // Sending unallowed data, kill content. 1.169 + NS_ENSURE_SUCCESS(rv, false); 1.170 + NS_ENSURE_TRUE(allowed, false); 1.171 + 1.172 + rv = mSocket->SendWithAddress(&aAddr, aData.Elements(), 1.173 + aData.Length(), &count); 1.174 + mozilla::unused << 1.175 + PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"), 1.176 + UDPSendResult(rv), 1.177 + NS_LITERAL_CSTRING("connected")); 1.178 + NS_ENSURE_SUCCESS(rv, true); 1.179 + NS_ENSURE_TRUE(count > 0, true); 1.180 + return true; 1.181 +} 1.182 + 1.183 +bool 1.184 +UDPSocketParent::RecvClose() 1.185 +{ 1.186 + NS_ENSURE_TRUE(mSocket, true); 1.187 + nsresult rv = mSocket->Close(); 1.188 + mSocket = nullptr; 1.189 + NS_ENSURE_SUCCESS(rv, true); 1.190 + return true; 1.191 +} 1.192 + 1.193 +bool 1.194 +UDPSocketParent::RecvRequestDelete() 1.195 +{ 1.196 + mozilla::unused << Send__delete__(this); 1.197 + return true; 1.198 +} 1.199 + 1.200 +void 1.201 +UDPSocketParent::ActorDestroy(ActorDestroyReason why) 1.202 +{ 1.203 + MOZ_ASSERT(mIPCOpen); 1.204 + mIPCOpen = false; 1.205 + if (mSocket) { 1.206 + mSocket->Close(); 1.207 + } 1.208 + mSocket = nullptr; 1.209 +} 1.210 + 1.211 +// nsIUDPSocketListener 1.212 + 1.213 +NS_IMETHODIMP 1.214 +UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage) 1.215 +{ 1.216 + // receiving packet from remote host, forward the message content to child process 1.217 + if (!mIPCOpen) { 1.218 + return NS_OK; 1.219 + } 1.220 + NS_ASSERTION(mFilter, "No packet filter"); 1.221 + 1.222 + uint16_t port; 1.223 + nsCString ip; 1.224 + nsCOMPtr<nsINetAddr> fromAddr; 1.225 + aMessage->GetFromAddr(getter_AddRefs(fromAddr)); 1.226 + fromAddr->GetPort(&port); 1.227 + fromAddr->GetAddress(ip); 1.228 + 1.229 + nsCString data; 1.230 + aMessage->GetData(data); 1.231 + 1.232 + const char* buffer = data.get(); 1.233 + uint32_t len = data.Length(); 1.234 + 1.235 + bool allowed; 1.236 + mozilla::net::NetAddr addr; 1.237 + fromAddr->GetNetAddr(&addr); 1.238 + nsresult rv = mFilter->FilterPacket(&addr, 1.239 + (const uint8_t*)buffer, len, 1.240 + nsIUDPSocketFilter::SF_INCOMING, 1.241 + &allowed); 1.242 + // Receiving unallowed data, drop. 1.243 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.244 + NS_ENSURE_TRUE(allowed, NS_OK); 1.245 + 1.246 + FallibleTArray<uint8_t> fallibleArray; 1.247 + if (!fallibleArray.InsertElementsAt(0, buffer, len)) { 1.248 + FireInternalError(this, __LINE__); 1.249 + return NS_ERROR_OUT_OF_MEMORY; 1.250 + } 1.251 + InfallibleTArray<uint8_t> infallibleArray; 1.252 + infallibleArray.SwapElements(fallibleArray); 1.253 + 1.254 + // compose callback 1.255 + mozilla::unused << 1.256 + PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("ondata"), 1.257 + UDPMessage(ip, port, infallibleArray), 1.258 + NS_LITERAL_CSTRING("connected")); 1.259 + 1.260 + return NS_OK; 1.261 +} 1.262 + 1.263 +NS_IMETHODIMP 1.264 +UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus) 1.265 +{ 1.266 + // underlying socket is dead, send state update to child process 1.267 + if (mIPCOpen) { 1.268 + mozilla::unused << 1.269 + PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onclose"), 1.270 + mozilla::void_t(), 1.271 + NS_LITERAL_CSTRING("closed")); 1.272 + } 1.273 + return NS_OK; 1.274 +} 1.275 + 1.276 +} // namespace dom 1.277 +} // namespace mozilla