// Runs on STS thread void UDPSocketParent::DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket, nsCOMPtr<nsIEventTarget>& aReturnThread, const UDPAddressInfo& aAddressInfo) { UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port())); if (NS_FAILED(ConnectInternal(aAddressInfo.addr(), aAddressInfo.port()))) { SendInternalError(aReturnThread, __LINE__); return; } CheckSTSThread(); nsCOMPtr<nsINetAddr> localAddr; aSocket->GetLocalAddr(getter_AddRefs(localAddr)); nsCString addr; if (NS_FAILED(localAddr->GetAddress(addr))) { SendInternalError(aReturnThread, __LINE__); return; } uint16_t port; if (NS_FAILED(localAddr->GetPort(&port))) { SendInternalError(aReturnThread, __LINE__); return; } UDPSOCKET_LOG(("%s: SendConnectResponse: %s:%u", __FUNCTION__, addr.get(), port)); SendConnectResponse(aReturnThread, UDPAddressInfo(addr, port)); }
bool UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo, const bool& aAddressReuse, const bool& aLoopback) { UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port())); if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) { FireInternalError(__LINE__); return true; } nsCOMPtr<nsINetAddr> localAddr; mSocket->GetLocalAddr(getter_AddRefs(localAddr)); nsCString addr; if (NS_FAILED(localAddr->GetAddress(addr))) { FireInternalError(__LINE__); return true; } uint16_t port; if (NS_FAILED(localAddr->GetPort(&port))) { FireInternalError(__LINE__); return true; } UDPSOCKET_LOG(("%s: SendCallbackOpened: %s:%u", __FUNCTION__, addr.get(), port)); mozilla::unused << SendCallbackOpened(UDPAddressInfo(addr, port)); return true; }
NS_IMETHODIMP UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage) { // receiving packet from remote host, forward the message content to child process if (!mIPCOpen) { return NS_OK; } uint16_t port; nsCString ip; nsCOMPtr<nsINetAddr> fromAddr; aMessage->GetFromAddr(getter_AddRefs(fromAddr)); fromAddr->GetPort(&port); fromAddr->GetAddress(ip); nsCString data; aMessage->GetData(data); const char* buffer = data.get(); uint32_t len = data.Length(); UDPSOCKET_LOG(("%s: %s:%u, length %u", __FUNCTION__, ip.get(), port, len)); if (mFilter) { bool allowed; mozilla::net::NetAddr addr; fromAddr->GetNetAddr(&addr); nsresult rv = mFilter->FilterPacket(&addr, (const uint8_t*)buffer, len, nsIUDPSocketFilter::SF_INCOMING, &allowed); // Receiving unallowed data, drop. if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) { if (!allowed) { UDPSOCKET_LOG(("%s: not allowed", __FUNCTION__)); } return NS_OK; } } FallibleTArray<uint8_t> fallibleArray; if (!fallibleArray.InsertElementsAt(0, buffer, len)) { FireInternalError(__LINE__); return NS_ERROR_OUT_OF_MEMORY; } InfallibleTArray<uint8_t> infallibleArray; infallibleArray.SwapElements(fallibleArray); // compose callback mozilla::unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray); return NS_OK; }
nsresult UDPSocketParent::ConnectInternal(const nsCString& aHost, const uint16_t& aPort) { nsresult rv; UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort)); if (!mSocket) { return NS_ERROR_NOT_AVAILABLE; } PRNetAddr prAddr; memset(&prAddr, 0, sizeof(prAddr)); PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr); PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr); if (status != PR_SUCCESS) { return NS_ERROR_FAILURE; } mozilla::net::NetAddr addr; PRNetAddrToNetAddr(&prAddr, &addr); rv = mSocket->Connect(&addr); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; }
void UDPSocketParent::SendInternalError(nsIEventTarget* aThread, uint32_t aLineNo) { UDPSOCKET_LOG(("SendInternalError: %u", aLineNo)); Unused << NS_WARN_IF(NS_FAILED(aThread->Dispatch( WrapRunnable(RefPtr<UDPSocketParent>(this), &UDPSocketParent::FireInternalError, aLineNo), NS_DISPATCH_NORMAL))); }
nsresult UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort, const bool& aAddressReuse, const bool& aLoopback) { nsresult rv; UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort)); nsCOMPtr<nsIUDPSocket> sock = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (aHost.IsEmpty()) { rv = sock->Init(aPort, false, mPrincipal, aAddressReuse, /* optional_argc = */ 1); } else { PRNetAddr prAddr; PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr); PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr); if (status != PR_SUCCESS) { return NS_ERROR_FAILURE; } mozilla::net::NetAddr addr; PRNetAddrToNetAddr(&prAddr, &addr); rv = sock->InitWithAddress(&addr, mPrincipal, aAddressReuse, /* optional_argc = */ 1); } if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = sock->SetMulticastLoopback(aLoopback); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // register listener rv = sock->AsyncListen(this); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } mSocket = sock; return NS_OK; }
void nsUDPSocket::OnMsgAttach() { UDPSOCKET_LOG(("nsUDPSocket::OnMsgAttach [this=%p]\n", this)); if (NS_FAILED(mCondition)) return; mCondition = TryAttach(); // if we hit an error while trying to attach then bail... if (NS_FAILED(mCondition)) { NS_ASSERTION(!mAttached, "should not be attached already"); OnSocketDetached(mFD); } }
void nsUDPSocket::OnMsgClose() { UDPSOCKET_LOG(("nsUDPSocket::OnMsgClose [this=%p]\n", this)); if (NS_FAILED(mCondition)) return; // tear down socket. this signals the STS to detach our socket handler. mCondition = NS_BINDING_ABORTED; // if we are attached, then socket transport service will call our // OnSocketDetached method automatically. Otherwise, we have to call it // (and thus close the socket) manually. if (!mAttached) OnSocketDetached(mFD); }
nsresult UDPSocket::InitLocal(const nsAString& aLocalAddress, const uint16_t& aLocalPort) { nsresult rv; nsCOMPtr<nsIUDPSocket> sock = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner(), &rv); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull(); if (!principal) { return NS_ERROR_FAILURE; } if (aLocalAddress.IsEmpty()) { rv = sock->Init(aLocalPort, /* loopback = */ false, principal, mAddressReuse, /* optionalArgc = */ 1); } else { PRNetAddr prAddr; PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr); PR_StringToNetAddr(NS_ConvertUTF16toUTF8(aLocalAddress).BeginReading(), &prAddr); UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, NS_ConvertUTF16toUTF8(aLocalAddress).get(), aLocalPort)); mozilla::net::NetAddr addr; PRNetAddrToNetAddr(&prAddr, &addr); rv = sock->InitWithAddress(&addr, principal, mAddressReuse, /* optionalArgc = */ 1); } if (NS_FAILED(rv)) { return rv; } rv = sock->SetMulticastLoopback(mLoopback); if (NS_FAILED(rv)) { return rv; } mSocket = sock; // Get real local address and local port nsCOMPtr<nsINetAddr> localAddr; rv = mSocket->GetLocalAddr(getter_AddRefs(localAddr)); if (NS_FAILED(rv)) { return rv; } nsCString localAddress; rv = localAddr->GetAddress(localAddress); if (NS_FAILED(rv)) { return rv; } mLocalAddress = NS_ConvertUTF8toUTF16(localAddress); uint16_t localPort; rv = localAddr->GetPort(&localPort); if (NS_FAILED(rv)) { return rv; } mLocalPort.SetValue(localPort); mListenerProxy = new ListenerProxy(this); rv = mSocket->AsyncListen(mListenerProxy); if (NS_FAILED(rv)) { return rv; } mReadyState = SocketReadyState::Open; rv = DoPendingMcastCommand(); if (NS_FAILED(rv)) { return rv; } mOpened->MaybeResolve(JS::UndefinedHandleValue); return NS_OK; }
bool UDPSocket::Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData, const Optional<nsAString>& aRemoteAddress, const Optional<Nullable<uint16_t>>& aRemotePort, ErrorResult& aRv) { if (mReadyState != SocketReadyState::Open) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return false; } MOZ_ASSERT(mSocket || mSocketChild); // If the remote address and port were not specified in the constructor or as arguments, // throw InvalidAccessError. nsCString remoteAddress; if (aRemoteAddress.WasPassed()) { remoteAddress = NS_ConvertUTF16toUTF8(aRemoteAddress.Value()); UDPSOCKET_LOG(("%s: Send to %s", __FUNCTION__, remoteAddress.get())); } else if (!mRemoteAddress.IsVoid()) { remoteAddress = mRemoteAddress; UDPSOCKET_LOG(("%s: Send to %s", __FUNCTION__, remoteAddress.get())); } else { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return false; } uint16_t remotePort; if (aRemotePort.WasPassed() && !aRemotePort.Value().IsNull()) { remotePort = aRemotePort.Value().Value(); } else if (!mRemotePort.IsNull()) { remotePort = mRemotePort.Value(); } else { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return false; } nsCOMPtr<nsIInputStream> stream; if (aData.IsBlob()) { Blob& blob = aData.GetAsBlob(); blob.GetInternalStream(getter_AddRefs(stream), aRv); if (NS_WARN_IF(aRv.Failed())) { return false; } } else { nsresult rv; nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.Throw(rv); return false; } if (aData.IsString()) { NS_ConvertUTF16toUTF8 data(aData.GetAsString()); aRv = strStream->SetData(data.BeginReading(), data.Length()); } else if (aData.IsArrayBuffer()) { const ArrayBuffer& data = aData.GetAsArrayBuffer(); data.ComputeLengthAndData(); aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length()); } else { const ArrayBufferView& data = aData.GetAsArrayBufferView(); data.ComputeLengthAndData(); aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length()); } if (NS_WARN_IF(aRv.Failed())) { return false; } stream = strStream; } if (mSocket) { aRv = mSocket->SendBinaryStream(remoteAddress, remotePort, stream); } else if (mSocketChild) { aRv = mSocketChild->SendBinaryStream(remoteAddress, remotePort, stream); } if (NS_WARN_IF(aRv.Failed())) { return false; } return true; }
nsresult UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort, const bool& aAddressReuse, const bool& aLoopback, const uint32_t& recvBufferSize, const uint32_t& sendBufferSize) { nsresult rv; UDPSOCKET_LOG(("%s: [this=%p] %s:%u addressReuse: %d loopback: %d recvBufferSize: %lu, sendBufferSize: %lu", __FUNCTION__, this, nsCString(aHost).get(), aPort, aAddressReuse, aLoopback, recvBufferSize, sendBufferSize)); nsCOMPtr<nsIUDPSocket> sock = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (aHost.IsEmpty()) { rv = sock->Init(aPort, false, mPrincipal, aAddressReuse, /* optional_argc = */ 1); } else { PRNetAddr prAddr; PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr); PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr); if (status != PR_SUCCESS) { return NS_ERROR_FAILURE; } mozilla::net::NetAddr addr; PRNetAddrToNetAddr(&prAddr, &addr); rv = sock->InitWithAddress(&addr, mPrincipal, aAddressReuse, /* optional_argc = */ 1); } if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsCOMPtr<nsINetAddr> laddr; rv = sock->GetLocalAddr(getter_AddRefs(laddr)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } uint16_t family; rv = laddr->GetFamily(&family); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (family == nsINetAddr::FAMILY_INET) { rv = sock->SetMulticastLoopback(aLoopback); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } // TODO: once bug 1252759 is fixed query buffer first and only increase if (recvBufferSize != 0) { rv = sock->SetRecvBufferSize(recvBufferSize); if (NS_WARN_IF(NS_FAILED(rv))) { UDPSOCKET_LOG(("%s: [this=%p] %s:%u failed to set recv buffer size to: %lu", __FUNCTION__, this, nsCString(aHost).get(), aPort, recvBufferSize)); } } if (sendBufferSize != 0) { rv = sock->SetSendBufferSize(sendBufferSize); if (NS_WARN_IF(NS_FAILED(rv))) { UDPSOCKET_LOG(("%s: [this=%p] %s:%u failed to set send buffer size to: %lu", __FUNCTION__, this, nsCString(aHost).get(), aPort, sendBufferSize)); } } // register listener rv = sock->AsyncListen(this); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } mSocket = sock; return NS_OK; }