From a3ff2ad0acbd024064e61ad7bde50d6c5bcc3a04 Mon Sep 17 00:00:00 2001 From: Shih-Chiang Chien Date: Fri, 10 May 2013 20:00:22 +0800 Subject: [PATCH] Bug 869869 - Part 1, change nsUDPServerSocket to nsUDPSocket, r=mcmanus. --HG-- rename : netwerk/base/public/nsIUDPServerSocket.idl => netwerk/base/public/nsIUDPSocket.idl rename : netwerk/base/src/nsUDPServerSocket.cpp => netwerk/base/src/nsUDPSocket.cpp rename : netwerk/base/src/nsUDPServerSocket.h => netwerk/base/src/nsUDPSocket.h --- dom/push/src/PushService.jsm | 2 +- netwerk/base/public/moz.build | 2 +- netwerk/base/public/nsINetAddr.idl | 12 +- ...sIUDPServerSocket.idl => nsIUDPSocket.idl} | 108 ++++-- netwerk/base/src/moz.build | 2 +- netwerk/base/src/nsNetAddr.cpp | 5 + ...{nsUDPServerSocket.cpp => nsUDPSocket.cpp} | 310 ++++++++++++++---- .../{nsUDPServerSocket.h => nsUDPSocket.h} | 24 +- netwerk/build/nsNetCID.h | 8 +- netwerk/build/nsNetModule.cpp | 10 +- netwerk/test/TestUDPSocket.cpp | 268 +++++++++++++++ netwerk/test/moz.build | 2 +- 12 files changed, 627 insertions(+), 126 deletions(-) rename netwerk/base/public/{nsIUDPServerSocket.idl => nsIUDPSocket.idl} (50%) rename netwerk/base/src/{nsUDPServerSocket.cpp => nsUDPSocket.cpp} (63%) rename netwerk/base/src/{nsUDPServerSocket.h => nsUDPSocket.h} (83%) create mode 100644 netwerk/test/TestUDPSocket.cpp diff --git a/dom/push/src/PushService.jsm b/dom/push/src/PushService.jsm index da494e8c8a4..b34e9aeafea 100644 --- a/dom/push/src/PushService.jsm +++ b/dom/push/src/PushService.jsm @@ -1434,7 +1434,7 @@ this.PushService = { return; } - this._udpServer = Cc["@mozilla.org/network/server-socket-udp;1"] + this._udpServer = Cc["@mozilla.org/network/socket-udp;1"] .createInstance(Ci.nsIUDPServerSocket); this._udpServer.init(-1, false); this._udpServer.asyncListen(this); diff --git a/netwerk/base/public/moz.build b/netwerk/base/public/moz.build index ee79dcfb48a..fcb43c92ff2 100644 --- a/netwerk/base/public/moz.build +++ b/netwerk/base/public/moz.build @@ -106,7 +106,7 @@ XPIDL_SOURCES += [ 'nsITimedChannel.idl', 'nsITraceableChannel.idl', 'nsITransport.idl', - 'nsIUDPServerSocket.idl', + 'nsIUDPSocket.idl', 'nsIUnicharStreamLoader.idl', 'nsIUploadChannel.idl', 'nsIUploadChannel2.idl', diff --git a/netwerk/base/public/nsINetAddr.idl b/netwerk/base/public/nsINetAddr.idl index 890ee821768..c41a9b71f19 100644 --- a/netwerk/base/public/nsINetAddr.idl +++ b/netwerk/base/public/nsINetAddr.idl @@ -6,13 +6,18 @@ #include "nsISupports.idl" +%{ C++ +#include "mozilla/net/DNS.h" +%} +native NetAddr(mozilla::net::NetAddr); + /** * nsINetAddr * * This interface represents a native NetAddr struct in a readonly * interface. */ -[scriptable, uuid(4f7c40b0-fc7d-42a4-a642-1b2a703c10f6)] +[scriptable, uuid(652B9EC5-D159-45D7-9127-50BB559486CD)] interface nsINetAddr : nsISupports { /** @@ -71,4 +76,9 @@ interface nsINetAddr : nsISupports const unsigned long FAMILY_INET = 1; const unsigned long FAMILY_INET6 = 2; const unsigned long FAMILY_LOCAL = 3; + + /** + * @return the underlying NetAddr struct. + */ + [noscript] NetAddr getNetAddr(); }; diff --git a/netwerk/base/public/nsIUDPServerSocket.idl b/netwerk/base/public/nsIUDPSocket.idl similarity index 50% rename from netwerk/base/public/nsIUDPServerSocket.idl rename to netwerk/base/public/nsIUDPSocket.idl index 5287f1e0143..f652393c9a9 100644 --- a/netwerk/base/public/nsIUDPServerSocket.idl +++ b/netwerk/base/public/nsIUDPSocket.idl @@ -6,7 +6,7 @@ #include "nsISupports.idl" interface nsINetAddr; -interface nsIUDPServerSocketListener; +interface nsIUDPSocketListener; interface nsIUDPMessage; interface nsISocketTransport; interface nsIOutputStream; @@ -22,23 +22,23 @@ native NetAddr(mozilla::net::NetAddr); [ptr] native NetAddrPtr(mozilla::net::NetAddr); /** - * nsIUDPServerSocket + * nsIUDPSocket * - * An interface to a server socket that can accept incoming connections. + * An interface to a UDP socket that can accept incoming connections. */ -[scriptable, uuid(c2a38bd0-024b-4ae8-bcb2-20d766b54389)] -interface nsIUDPServerSocket : nsISupports +[scriptable, uuid(6EFE692D-F0B0-4A9E-9E63-837C7452446D)] +interface nsIUDPSocket : nsISupports { /** * init * - * This method initializes a server socket. + * This method initializes a UDP socket. * * @param aPort - * The port of the server socket. Pass -1 to indicate no preference, + * The port of the UDP socket. Pass -1 to indicate no preference, * and a port will be selected automatically. * @param aLoopbackOnly - * If true, the server socket will only respond to connections on the + * If true, the UDP socket will only respond to connections on the * local loopback interface. Otherwise, it will accept connections * from any interface. To specify a particular network interface, * use initWithAddress. @@ -48,20 +48,20 @@ interface nsIUDPServerSocket : nsISupports /** * initWithAddress * - * This method initializes a server socket, and binds it to a particular + * This method initializes a UDP socket, and binds it to a particular * local address (and hence a particular local network interface). * * @param aAddr - * The address to which this server socket should be bound. + * The address to which this UDP socket should be bound. */ [noscript] void initWithAddress([const] in NetAddrPtr aAddr); /** * close * - * This method closes a server socket. This does not affect already + * This method closes a UDP socket. This does not affect already * connected client sockets (i.e., the nsISocketTransport instances - * created from this server socket). This will cause the onStopListening + * created from this UDP socket). This will cause the onStopListening * event to asynchronously fire with a status of NS_BINDING_ABORTED. */ void close(); @@ -69,7 +69,7 @@ interface nsIUDPServerSocket : nsISupports /** * asyncListen * - * This method puts the server socket in the listening state. It will + * This method puts the UDP socket in the listening state. It will * asynchronously listen for and accept client connections. The listener * will be notified once for each client connection that is accepted. The * listener's onSocketAccepted method will be called on the same thread @@ -81,65 +81,109 @@ interface nsIUDPServerSocket : nsISupports * @param aListener * The listener to be notified when client connections are accepted. */ - void asyncListen(in nsIUDPServerSocketListener aListener); + void asyncListen(in nsIUDPSocketListener aListener); /** - * Returns the port of this server socket. + * Returns the port of this UDP socket. */ readonly attribute long port; /** - * Returns the address to which this server socket is bound. Since a - * server socket may be bound to multiple network devices, this address + * Returns the address to which this UDP socket is bound. Since a + * UDP socket may be bound to multiple network devices, this address * may not necessarily be specific to a single network device. In the * case of an IP socket, the IP address field would be zerod out to - * indicate a server socket bound to all network devices. Therefore, + * indicate a UDP socket bound to all network devices. Therefore, * this method cannot be used to determine the IP address of the local * system. See nsIDNSService::myHostName if this is what you need. */ [noscript] NetAddr getAddress(); + + /** + * send + * + * Send out the datagram to specified remote host and port. + * DNS lookup will be triggered. + * + * @param host The remote host name. + * @param port The remote port. + * @param data The buffer containing the data to be written. + * @param dataLength The maximum number of bytes to be written. + * @return number of bytes written. (0 or dataLength) + */ + unsigned long send(in AUTF8String host, in unsigned short port, + [const, array, size_is(dataLength)]in uint8_t data, + in unsigned long dataLength); + + /** + * sendWithAddr + * + * Send out the datagram to specified remote host and port. + * + * @param addr The remote host address. + * @param data The buffer containing the data to be written. + * @param dataLength The maximum number of bytes to be written. + * @return number of bytes written. (0 or dataLength) + */ + unsigned long sendWithAddr(in nsINetAddr addr, + [const, array, size_is(dataLength)]in uint8_t data, + in unsigned long dataLength); + + /** + * sendWithAddress + * + * Send out the datagram to specified remote address and port. + * + * @param addr The remote host address. + * @param data The buffer containing the data to be written. + * @param dataLength The maximum number of bytes to be written. + * @return number of bytes written. (0 or dataLength) + */ + [noscript] unsigned long sendWithAddress([const] in NetAddrPtr addr, + [const, array, size_is(dataLength)]in uint8_t data, + in unsigned long dataLength); }; /** - * nsIUDPServerSocketListener + * nsIUDPSocketListener * - * This interface is notified whenever a server socket accepts a new connection. + * This interface is notified whenever a UDP socket accepts a new connection. * The transport is in the connected state, and read/write streams can be opened * using the normal nsITransport API. The address of the client can be found by * calling the nsISocketTransport::GetAddress method or by inspecting * nsISocketTransport::GetHost, which returns a string representation of the * client's IP address (NOTE: this may be an IPv4 or IPv6 string literal). */ -[scriptable, uuid(0500a336-29b2-4df1-9103-911f8ee0a569)] -interface nsIUDPServerSocketListener : nsISupports +[scriptable, uuid(2E4B5DD3-7358-4281-B81F-10C62EF39CB5)] +interface nsIUDPSocketListener : nsISupports { /** * onPacketReceived * * This method is called when a client sends an UDP packet. * - * @param aServ - * The server socket. + * @param aSocket + * The UDP socket. * @param aMessage * The message. */ - void onPacketReceived(in nsIUDPServerSocket aServ, + void onPacketReceived(in nsIUDPSocket aSocket, in nsIUDPMessage aMessage); /** * onStopListening * * This method is called when the listening socket stops for some reason. - * The server socket is effectively dead after this notification. + * The UDP socket is effectively dead after this notification. * - * @param aServ - * The server socket. + * @param aSocket + * The UDP socket. * @param aStatus - * The reason why the server socket stopped listening. If the - * server socket was manually closed, then this value will be + * The reason why the UDP socket stopped listening. If the + * UDP socket was manually closed, then this value will be * NS_BINDING_ABORTED. */ - void onStopListening(in nsIUDPServerSocket aServ, in nsresult aStatus); + void onStopListening(in nsIUDPSocket aSocket, in nsresult aStatus); }; /** @@ -147,7 +191,7 @@ interface nsIUDPServerSocketListener : nsISupports * * This interface is used to encapsulate an incomming UDP message */ -[scriptable, uuid(1587698a-60b6-4a8d-9df9-708cd793e24b)] +[scriptable, uuid(333D5D69-8117-4AA6-9E16-2DD4FD6AEBA6)] interface nsIUDPMessage : nsISupports { /** diff --git a/netwerk/base/src/moz.build b/netwerk/base/src/moz.build index be976c4e75a..69812accc22 100644 --- a/netwerk/base/src/moz.build +++ b/netwerk/base/src/moz.build @@ -66,7 +66,7 @@ SOURCES += [ 'nsSyncStreamListener.cpp', 'nsTemporaryFileInputStream.cpp', 'nsTransportUtils.cpp', - 'nsUDPServerSocket.cpp', + 'nsUDPSocket.cpp', 'nsUnicharStreamLoader.cpp', 'nsURIChecker.cpp', 'nsURLHelper.cpp', diff --git a/netwerk/base/src/nsNetAddr.cpp b/netwerk/base/src/nsNetAddr.cpp index bd2babd179c..e516340ee16 100644 --- a/netwerk/base/src/nsNetAddr.cpp +++ b/netwerk/base/src/nsNetAddr.cpp @@ -151,3 +151,8 @@ NS_IMETHODIMP nsNetAddr::GetIsV4Mapped(bool *aIsV4Mapped) return NS_OK; } +NS_IMETHODIMP nsNetAddr::GetNetAddr(NetAddr *aResult) { + memcpy(aResult, &mAddr, sizeof(mAddr)); + return NS_OK; +} + diff --git a/netwerk/base/src/nsUDPServerSocket.cpp b/netwerk/base/src/nsUDPSocket.cpp similarity index 63% rename from netwerk/base/src/nsUDPServerSocket.cpp rename to netwerk/base/src/nsUDPSocket.cpp index 526d1efdb38..dab5bdf4cd9 100644 --- a/netwerk/base/src/nsUDPServerSocket.cpp +++ b/netwerk/base/src/nsUDPSocket.cpp @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsSocketTransport2.h" -#include "nsUDPServerSocket.h" +#include "nsUDPSocket.h" #include "nsProxyRelease.h" #include "nsAutoPtr.h" #include "nsError.h" @@ -19,6 +19,9 @@ #include "nsIPipe.h" #include "prerror.h" #include "nsThreadUtils.h" +#include "nsIDNSRecord.h" +#include "nsIDNSService.h" +#include "nsICancelable.h" using namespace mozilla::net; using namespace mozilla; @@ -27,10 +30,10 @@ static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); //----------------------------------------------------------------------------- -typedef void (nsUDPServerSocket:: *nsUDPServerSocketFunc)(void); +typedef void (nsUDPSocket:: *nsUDPSocketFunc)(void); static nsresult -PostEvent(nsUDPServerSocket *s, nsUDPServerSocketFunc func) +PostEvent(nsUDPSocket *s, nsUDPSocketFunc func) { nsCOMPtr ev = NS_NewRunnableMethod(s, func); @@ -40,15 +43,32 @@ PostEvent(nsUDPServerSocket *s, nsUDPServerSocketFunc func) return gSocketTransportService->Dispatch(ev, NS_DISPATCH_NORMAL); } +static nsresult +ResolveHost(const nsACString &host, nsIDNSListener *listener) +{ + nsresult rv; + + nsCOMPtr dns = + do_GetService("@mozilla.org/network/dns-service;1", &rv); + if (NS_FAILED(rv)) { + return rv; + } + + nsCOMPtr tmpOutstanding; + return dns->AsyncResolve(host, 0, listener, nullptr, + getter_AddRefs(tmpOutstanding)); + +} + //----------------------------------------------------------------------------- -// nsUPDOutputStream impl +// nsUDPOutputStream impl //----------------------------------------------------------------------------- NS_IMPL_ISUPPORTS1(nsUDPOutputStream, nsIOutputStream) -nsUDPOutputStream::nsUDPOutputStream(nsUDPServerSocket* aServer, +nsUDPOutputStream::nsUDPOutputStream(nsUDPSocket* aSocket, PRFileDesc* aFD, PRNetAddr& aPrClientAddr) - : mServer(aServer) + : mSocket(aSocket) , mFD(aFD) , mPrClientAddr(aPrClientAddr) , mIsClosed(false) @@ -90,7 +110,7 @@ NS_IMETHODIMP nsUDPOutputStream::Write(const char * aBuf, uint32_t aCount, uint3 *_retval = count; - mServer->AddOutputBytes(count); + mSocket->AddOutputBytes(count); return NS_OK; } @@ -115,7 +135,7 @@ NS_IMETHODIMP nsUDPOutputStream::IsNonBlocking(bool *_retval) } //----------------------------------------------------------------------------- -// nsUPDMessage impl +// nsUDPMessage impl //----------------------------------------------------------------------------- NS_IMPL_ISUPPORTS1(nsUDPMessage, nsIUDPMessage) @@ -162,11 +182,11 @@ NS_IMETHODIMP nsUDPMessage::GetOutputStream(nsIOutputStream * *aOutputStream) } //----------------------------------------------------------------------------- -// nsServerSocket +// nsUDPSocket //----------------------------------------------------------------------------- -nsUDPServerSocket::nsUDPServerSocket() - : mLock("nsUDPServerSocket.mLock") +nsUDPSocket::nsUDPSocket() + : mLock("nsUDPSocket.mLock") , mFD(nullptr) , mAttached(false) , mByteReadCount(0) @@ -183,26 +203,26 @@ nsUDPServerSocket::nsUDPServerSocket() } mSts = gSocketTransportService; - MOZ_COUNT_CTOR(nsUDPServerSocket); + MOZ_COUNT_CTOR(nsUDPSocket); } -nsUDPServerSocket::~nsUDPServerSocket() +nsUDPSocket::~nsUDPSocket() { Close(); // just in case :) - MOZ_COUNT_DTOR(nsUDPServerSocket); + MOZ_COUNT_DTOR(nsUDPSocket); } void -nsUDPServerSocket::AddOutputBytes(uint64_t aBytes) +nsUDPSocket::AddOutputBytes(uint64_t aBytes) { mByteWriteCount += aBytes; } void -nsUDPServerSocket::OnMsgClose() +nsUDPSocket::OnMsgClose() { - SOCKET_LOG(("nsServerSocket::OnMsgClose [this=%p]\n", this)); + SOCKET_LOG(("nsUDPSocket::OnMsgClose [this=%p]\n", this)); if (NS_FAILED(mCondition)) return; @@ -218,9 +238,9 @@ nsUDPServerSocket::OnMsgClose() } void -nsUDPServerSocket::OnMsgAttach() +nsUDPSocket::OnMsgAttach() { - SOCKET_LOG(("nsServerSocket::OnMsgAttach [this=%p]\n", this)); + SOCKET_LOG(("nsUDPSocket::OnMsgAttach [this=%p]\n", this)); if (NS_FAILED(mCondition)) return; @@ -236,7 +256,7 @@ nsUDPServerSocket::OnMsgAttach() } nsresult -nsUDPServerSocket::TryAttach() +nsUDPSocket::TryAttach() { nsresult rv; @@ -258,7 +278,7 @@ nsUDPServerSocket::TryAttach() if (!gSocketTransportService->CanAttachSocket()) { nsCOMPtr event = - NS_NewRunnableMethod(this, &nsUDPServerSocket::OnMsgAttach); + NS_NewRunnableMethod(this, &nsUDPSocket::OnMsgAttach); nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event); if (NS_FAILED(rv)) @@ -282,11 +302,11 @@ nsUDPServerSocket::TryAttach() } //----------------------------------------------------------------------------- -// nsServerSocket::nsASocketHandler +// nsUDPSocket::nsASocketHandler //----------------------------------------------------------------------------- void -nsUDPServerSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags) +nsUDPSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags) { NS_ASSERTION(NS_SUCCEEDED(mCondition), "oops"); NS_ASSERTION(mFD == fd, "wrong file descriptor"); @@ -343,7 +363,7 @@ nsUDPServerSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags) } void -nsUDPServerSocket::OnSocketDetached(PRFileDesc *fd) +nsUDPSocket::OnSocketDetached(PRFileDesc *fd) { // force a failure condition if none set; maybe the STS is shutting down :-/ if (NS_SUCCEEDED(mCondition)) @@ -359,7 +379,7 @@ nsUDPServerSocket::OnSocketDetached(PRFileDesc *fd) if (mListener) { // need to atomically clear mListener. see our Close() method. - nsCOMPtr listener; + nsCOMPtr listener; { MutexAutoLock lock(mLock); mListener.swap(listener); @@ -373,25 +393,25 @@ nsUDPServerSocket::OnSocketDetached(PRFileDesc *fd) } void -nsUDPServerSocket::IsLocal(bool *aIsLocal) +nsUDPSocket::IsLocal(bool *aIsLocal) { - // If bound to loopback, this server socket only accepts local connections. + // If bound to loopback, this UDP socket only accepts local connections. *aIsLocal = mAddr.raw.family == nsINetAddr::FAMILY_LOCAL; } //----------------------------------------------------------------------------- -// nsServerSocket::nsISupports +// nsSocket::nsISupports //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS1(nsUDPServerSocket, nsIUDPServerSocket) +NS_IMPL_ISUPPORTS1(nsUDPSocket, nsIUDPSocket) //----------------------------------------------------------------------------- -// nsServerSocket::nsIServerSocket +// nsSocket::nsISocket //----------------------------------------------------------------------------- NS_IMETHODIMP -nsUDPServerSocket::Init(int32_t aPort, bool aLoopbackOnly) +nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly) { NetAddr addr; @@ -410,7 +430,7 @@ nsUDPServerSocket::Init(int32_t aPort, bool aLoopbackOnly) } NS_IMETHODIMP -nsUDPServerSocket::InitWithAddress(const NetAddr *aAddr) +nsUDPSocket::InitWithAddress(const NetAddr *aAddr) { NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED); @@ -421,7 +441,7 @@ nsUDPServerSocket::InitWithAddress(const NetAddr *aAddr) mFD = PR_OpenUDPSocket(aAddr->raw.family); if (!mFD) { - NS_WARNING("unable to create server socket"); + NS_WARNING("unable to create UDP socket"); return NS_ERROR_FAILURE; } @@ -436,6 +456,7 @@ nsUDPServerSocket::InitWithAddress(const NetAddr *aAddr) PR_SetSocketOption(mFD, &opt); PRNetAddr addr; + PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr); NetAddrToPRNetAddr(aAddr, &addr); if (PR_Bind(mFD, &addr) != PR_SUCCESS) @@ -467,7 +488,7 @@ fail: } NS_IMETHODIMP -nsUDPServerSocket::Close() +nsUDPSocket::Close() { { MutexAutoLock lock(mLock); @@ -483,11 +504,11 @@ nsUDPServerSocket::Close() return NS_OK; } } - return PostEvent(this, &nsUDPServerSocket::OnMsgClose); + return PostEvent(this, &nsUDPSocket::OnMsgClose); } NS_IMETHODIMP -nsUDPServerSocket::GetPort(int32_t *aResult) +nsUDPSocket::GetPort(int32_t *aResult) { // no need to enter the lock here uint16_t port; @@ -503,7 +524,7 @@ nsUDPServerSocket::GetPort(int32_t *aResult) } NS_IMETHODIMP -nsUDPServerSocket::GetAddress(NetAddr *aResult) +nsUDPSocket::GetAddress(NetAddr *aResult) { // no need to enter the lock here memcpy(aResult, &mAddr, sizeof(mAddr)); @@ -512,107 +533,260 @@ nsUDPServerSocket::GetAddress(NetAddr *aResult) namespace { -class ServerSocketListenerProxy MOZ_FINAL : public nsIUDPServerSocketListener +class SocketListenerProxy MOZ_FINAL : public nsIUDPSocketListener { public: - ServerSocketListenerProxy(nsIUDPServerSocketListener* aListener) - : mListener(new nsMainThreadPtrHolder(aListener)) + SocketListenerProxy(nsIUDPSocketListener* aListener) + : mListener(new nsMainThreadPtrHolder(aListener)) , mTargetThread(do_GetCurrentThread()) { } NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIUDPSERVERSOCKETLISTENER + NS_DECL_NSIUDPSOCKETLISTENER class OnPacketReceivedRunnable : public nsRunnable { public: - OnPacketReceivedRunnable(const nsMainThreadPtrHandle& aListener, - nsIUDPServerSocket* aServ, - nsIUDPMessage* aMessage) + OnPacketReceivedRunnable(const nsMainThreadPtrHandle& aListener, + nsIUDPSocket* aSocket, + nsIUDPMessage* aMessage) : mListener(aListener) - , mServ(aServ) + , mSocket(aSocket) , mMessage(aMessage) { } NS_DECL_NSIRUNNABLE private: - nsMainThreadPtrHandle mListener; - nsCOMPtr mServ; + nsMainThreadPtrHandle mListener; + nsCOMPtr mSocket; nsCOMPtr mMessage; }; class OnStopListeningRunnable : public nsRunnable { public: - OnStopListeningRunnable(const nsMainThreadPtrHandle& aListener, - nsIUDPServerSocket* aServ, + OnStopListeningRunnable(const nsMainThreadPtrHandle& aListener, + nsIUDPSocket* aSocket, nsresult aStatus) : mListener(aListener) - , mServ(aServ) + , mSocket(aSocket) , mStatus(aStatus) { } NS_DECL_NSIRUNNABLE private: - nsMainThreadPtrHandle mListener; - nsCOMPtr mServ; + nsMainThreadPtrHandle mListener; + nsCOMPtr mSocket; nsresult mStatus; }; private: - nsMainThreadPtrHandle mListener; + nsMainThreadPtrHandle mListener; nsCOMPtr mTargetThread; }; -NS_IMPL_ISUPPORTS1(ServerSocketListenerProxy, - nsIUDPServerSocketListener) +NS_IMPL_ISUPPORTS1(SocketListenerProxy, + nsIUDPSocketListener) NS_IMETHODIMP -ServerSocketListenerProxy::OnPacketReceived(nsIUDPServerSocket* aServ, - nsIUDPMessage* aMessage) +SocketListenerProxy::OnPacketReceived(nsIUDPSocket* aSocket, + nsIUDPMessage* aMessage) { nsRefPtr r = - new OnPacketReceivedRunnable(mListener, aServ, aMessage); + new OnPacketReceivedRunnable(mListener, aSocket, aMessage); return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL); } NS_IMETHODIMP -ServerSocketListenerProxy::OnStopListening(nsIUDPServerSocket* aServ, - nsresult aStatus) +SocketListenerProxy::OnStopListening(nsIUDPSocket* aSocket, + nsresult aStatus) { nsRefPtr r = - new OnStopListeningRunnable(mListener, aServ, aStatus); + new OnStopListeningRunnable(mListener, aSocket, aStatus); return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL); } NS_IMETHODIMP -ServerSocketListenerProxy::OnPacketReceivedRunnable::Run() +SocketListenerProxy::OnPacketReceivedRunnable::Run() { - mListener->OnPacketReceived(mServ, mMessage); + mListener->OnPacketReceived(mSocket, mMessage); return NS_OK; } NS_IMETHODIMP -ServerSocketListenerProxy::OnStopListeningRunnable::Run() +SocketListenerProxy::OnStopListeningRunnable::Run() { - mListener->OnStopListening(mServ, mStatus); + mListener->OnStopListening(mSocket, mStatus); + return NS_OK; +} + +class PendingSend : public nsIDNSListener +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDNSLISTENER + + PendingSend(nsUDPSocket *aSocket, uint16_t aPort, + FallibleTArray &aData) + : mSocket(aSocket) + , mPort(aPort) + { + mData.SwapElements(aData); + } + + virtual ~PendingSend() {} + +private: + nsRefPtr mSocket; + uint16_t mPort; + FallibleTArray mData; +}; + +NS_IMPL_ISUPPORTS1(PendingSend, nsIDNSListener) + +NS_IMETHODIMP +PendingSend::OnLookupComplete(nsICancelable *request, + nsIDNSRecord *rec, + nsresult status) +{ + if (NS_FAILED(status)) { + NS_WARNING("Failed to send UDP packet due to DNS lookup failure"); + return NS_OK; + } + + NetAddr addr; + if (NS_SUCCEEDED(rec->GetNextAddr(mPort, &addr))) { + uint32_t count; + nsresult rv = mSocket->SendWithAddress(&addr, mData.Elements(), + mData.Length(), &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + +class SendRequestRunnable: public nsRunnable { +public: + SendRequestRunnable(nsUDPSocket *aSocket, + const NetAddr &aAddr, + FallibleTArray &aData) + : mSocket(aSocket) + , mAddr(aAddr) + , mData(aData) + { } + + NS_DECL_NSIRUNNABLE + +private: + nsRefPtr mSocket; + const NetAddr mAddr; + FallibleTArray mData; +}; + +NS_IMETHODIMP +SendRequestRunnable::Run() +{ + uint32_t count; + mSocket->SendWithAddress(&mAddr, mData.Elements(), + mData.Length(), &count); return NS_OK; } } // anonymous namespace NS_IMETHODIMP -nsUDPServerSocket::AsyncListen(nsIUDPServerSocketListener *aListener) +nsUDPSocket::AsyncListen(nsIUDPSocketListener *aListener) { // ensuring mFD implies ensuring mLock NS_ENSURE_TRUE(mFD, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(mListener == nullptr, NS_ERROR_IN_PROGRESS); { MutexAutoLock lock(mLock); - mListener = new ServerSocketListenerProxy(aListener); + mListener = new SocketListenerProxy(aListener); mListenerTarget = NS_GetCurrentThread(); } - return PostEvent(this, &nsUDPServerSocket::OnMsgAttach); + return PostEvent(this, &nsUDPSocket::OnMsgAttach); +} + +NS_IMETHODIMP +nsUDPSocket::Send(const nsACString &aHost, uint16_t aPort, + const uint8_t *aData, uint32_t aDataLength, + uint32_t *_retval) +{ + NS_ENSURE_ARG(aData); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = 0; + + FallibleTArray fallibleArray; + if (!fallibleArray.InsertElementsAt(0, aData, aDataLength)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsCOMPtr listener = new PendingSend(this, aPort, fallibleArray); + + nsresult rv = ResolveHost(aHost, listener); + NS_ENSURE_SUCCESS(rv, rv); + + *_retval = aDataLength; + return NS_OK; +} + +NS_IMETHODIMP +nsUDPSocket::SendWithAddr(nsINetAddr *aAddr, const uint8_t *aData, + uint32_t aDataLength, uint32_t *_retval) +{ + NS_ENSURE_ARG(aAddr); + NS_ENSURE_ARG(aData); + NS_ENSURE_ARG_POINTER(_retval); + + NetAddr netAddr; + aAddr->GetNetAddr(&netAddr); + return SendWithAddress(&netAddr, aData, aDataLength, _retval); +} + +NS_IMETHODIMP +nsUDPSocket::SendWithAddress(const NetAddr *aAddr, const uint8_t *aData, + uint32_t aDataLength, uint32_t *_retval) +{ + NS_ENSURE_ARG(aAddr); + NS_ENSURE_ARG(aData); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = 0; + + PRNetAddr prAddr; + NetAddrToPRNetAddr(aAddr, &prAddr); + + bool onSTSThread = false; + mSts->IsOnCurrentThread(&onSTSThread); + + if (onSTSThread) { + MutexAutoLock lock(mLock); + if (!mFD) { + // socket is not initialized or has been closed + return NS_ERROR_FAILURE; + } + int32_t count = PR_SendTo(mFD, aData, sizeof(uint8_t) *aDataLength, + 0, &prAddr, PR_INTERVAL_NO_WAIT); + if (count < 0) { + PRErrorCode code = PR_GetError(); + return ErrorAccordingToNSPR(code); + } + this->AddOutputBytes(count); + *_retval = count; + } else { + FallibleTArray fallibleArray; + if (!fallibleArray.InsertElementsAt(0, aData, aDataLength)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = mSts->Dispatch(new SendRequestRunnable(this, *aAddr, fallibleArray), + NS_DISPATCH_NORMAL); + NS_ENSURE_SUCCESS(rv, rv); + *_retval = aDataLength; + } + return NS_OK; } diff --git a/netwerk/base/src/nsUDPServerSocket.h b/netwerk/base/src/nsUDPSocket.h similarity index 83% rename from netwerk/base/src/nsUDPServerSocket.h rename to netwerk/base/src/nsUDPSocket.h index f82235ce770..b555505e1a0 100644 --- a/netwerk/base/src/nsUDPServerSocket.h +++ b/netwerk/base/src/nsUDPSocket.h @@ -3,22 +3,22 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef nsUDPServerSocket_h__ -#define nsUDPServerSocket_h__ +#ifndef nsUDPSocket_h__ +#define nsUDPSocket_h__ -#include "nsIUDPServerSocket.h" +#include "nsIUDPSocket.h" #include "mozilla/Mutex.h" #include "nsIOutputStream.h" #include "nsAutoPtr.h" //----------------------------------------------------------------------------- -class nsUDPServerSocket : public nsASocketHandler - , public nsIUDPServerSocket +class nsUDPSocket : public nsASocketHandler + , public nsIUDPSocket { public: NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIUDPSERVERSOCKET + NS_DECL_NSIUDPSOCKET // nsASocketHandler methods: virtual void OnSocketReady(PRFileDesc* fd, int16_t outFlags); @@ -30,10 +30,10 @@ public: void AddOutputBytes(uint64_t aBytes); - nsUDPServerSocket(); + nsUDPSocket(); // This must be public to support older compilers (xlC_r on AIX) - virtual ~nsUDPServerSocket(); + virtual ~nsUDPSocket(); private: void OnMsgClose(); @@ -47,7 +47,7 @@ private: mozilla::Mutex mLock; PRFileDesc *mFD; mozilla::net::NetAddr mAddr; - nsCOMPtr mListener; + nsCOMPtr mListener; nsCOMPtr mListenerTarget; bool mAttached; nsRefPtr mSts; @@ -85,16 +85,16 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIOUTPUTSTREAM - nsUDPOutputStream(nsUDPServerSocket* aServer, + nsUDPOutputStream(nsUDPSocket* aSocket, PRFileDesc* aFD, PRNetAddr& aPrClientAddr); virtual ~nsUDPOutputStream(); private: - nsRefPtr mServer; + nsRefPtr mSocket; PRFileDesc *mFD; PRNetAddr mPrClientAddr; bool mIsClosed; }; -#endif // nsUDPServerSocket_h__ +#endif // nsUDPSocket_h__ diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index 98fb0df8b79..ac3bf383e0d 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -335,10 +335,10 @@ {0xab, 0x1d, 0x5e, 0x68, 0xa9, 0xf4, 0x5f, 0x08} \ } -// component implementing nsIUDPServerSocket -#define NS_UDPSERVERSOCKET_CONTRACTID \ - "@mozilla.org/network/server-socket-udp;1" -#define NS_UDPSERVERSOCKET_CID \ +// component implementing nsIUDPSocket +#define NS_UDPSOCKET_CONTRACTID \ + "@mozilla.org/network/udp-socket;1" +#define NS_UDPSOCKET_CID \ { /* c9f74572-7b8e-4fec-bb4a-03c0d3021bd6 */ \ 0xc9f74572, \ 0x7b8e, \ diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index eaca702cb1c..c53cc6f3cc7 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -73,8 +73,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSocketTransportService, Init) #include "nsServerSocket.h" NS_GENERIC_FACTORY_CONSTRUCTOR(nsServerSocket) -#include "nsUDPServerSocket.h" -NS_GENERIC_FACTORY_CONSTRUCTOR(nsUDPServerSocket) +#include "nsUDPSocket.h" +NS_GENERIC_FACTORY_CONSTRUCTOR(nsUDPSocket) #include "nsUDPSocketProvider.h" NS_GENERIC_FACTORY_CONSTRUCTOR(nsUDPSocketProvider) @@ -682,7 +682,7 @@ NS_DEFINE_NAMED_CID(NS_IOSERVICE_CID); NS_DEFINE_NAMED_CID(NS_STREAMTRANSPORTSERVICE_CID); NS_DEFINE_NAMED_CID(NS_SOCKETTRANSPORTSERVICE_CID); NS_DEFINE_NAMED_CID(NS_SERVERSOCKET_CID); -NS_DEFINE_NAMED_CID(NS_UDPSERVERSOCKET_CID); +NS_DEFINE_NAMED_CID(NS_UDPSOCKET_CID); NS_DEFINE_NAMED_CID(NS_SOCKETPROVIDERSERVICE_CID); NS_DEFINE_NAMED_CID(NS_DNSSERVICE_CID); NS_DEFINE_NAMED_CID(NS_IDNSERVICE_CID); @@ -820,7 +820,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_STREAMTRANSPORTSERVICE_CID, false, nullptr, nsStreamTransportServiceConstructor }, { &kNS_SOCKETTRANSPORTSERVICE_CID, false, nullptr, nsSocketTransportServiceConstructor }, { &kNS_SERVERSOCKET_CID, false, nullptr, nsServerSocketConstructor }, - { &kNS_UDPSERVERSOCKET_CID, false, nullptr, nsUDPServerSocketConstructor }, + { &kNS_UDPSOCKET_CID, false, nullptr, nsUDPSocketConstructor }, { &kNS_SOCKETPROVIDERSERVICE_CID, false, nullptr, nsSocketProviderService::Create }, { &kNS_DNSSERVICE_CID, false, nullptr, nsDNSServiceConstructor }, { &kNS_IDNSERVICE_CID, false, nullptr, nsIDNServiceConstructor }, @@ -965,7 +965,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { { NS_STREAMTRANSPORTSERVICE_CONTRACTID, &kNS_STREAMTRANSPORTSERVICE_CID }, { NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &kNS_SOCKETTRANSPORTSERVICE_CID }, { NS_SERVERSOCKET_CONTRACTID, &kNS_SERVERSOCKET_CID }, - { NS_UDPSERVERSOCKET_CONTRACTID, &kNS_UDPSERVERSOCKET_CID }, + { NS_UDPSOCKET_CONTRACTID, &kNS_UDPSOCKET_CID }, { NS_SOCKETPROVIDERSERVICE_CONTRACTID, &kNS_SOCKETPROVIDERSERVICE_CID }, { NS_DNSSERVICE_CONTRACTID, &kNS_DNSSERVICE_CID }, { NS_IDNSERVICE_CONTRACTID, &kNS_IDNSERVICE_CID }, diff --git a/netwerk/test/TestUDPSocket.cpp b/netwerk/test/TestUDPSocket.cpp new file mode 100644 index 00000000000..62b676c3877 --- /dev/null +++ b/netwerk/test/TestUDPSocket.cpp @@ -0,0 +1,268 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestCommon.h" +#include "TestHarness.h" +#include "nsIUDPSocket.h" +#include "nsISocketTransportService.h" +#include "nsISocketTransport.h" +#include "nsIOutputStream.h" +#include "nsIInputStream.h" +#include "nsINetAddr.h" +#include "mozilla/net/DNS.h" +#include "prerror.h" + +#define REQUEST 0x68656c6f +#define RESPONSE 0x6f6c6568 + +#define EXPECT_SUCCESS(rv, ...) \ + PR_BEGIN_MACRO \ + if (NS_FAILED(rv)) { \ + fail(__VA_ARGS__); \ + return false; \ + } \ + PR_END_MACRO + + +#define EXPECT_FAILURE(rv, ...) \ + PR_BEGIN_MACRO \ + if (NS_SUCCEEDED(rv)) { \ + fail(__VA_ARGS__); \ + return false; \ + } \ + PR_END_MACRO + +#define REQUIRE_EQUAL(a, b, ...) \ + PR_BEGIN_MACRO \ + if (a != b) { \ + fail(__VA_ARGS__); \ + return false; \ + } \ + PR_END_MACRO + +enum TestPhase { + TEST_OUTPUT_STREAM, + TEST_SEND_API, + TEST_NONE +}; + +static TestPhase phase = TEST_NONE; + +static bool CheckMessageContent(nsIUDPMessage *aMessage, uint32_t aExpectedContent) +{ + nsCString data; + aMessage->GetData(data); + + const char* buffer = data.get(); + uint32_t len = data.Length(); + + uint32_t input = 0; + for (uint32_t i = 0; i < len; i++) { + input += buffer[i] << (8 * i); + } + + if (len != sizeof(uint32_t) || input != aExpectedContent) + { + fail("Request 0x%x received, expected 0x%x", input, aExpectedContent); + return false; + } else { + passed("Request 0x%x received as expected", input); + return true; + } +} + +/* + * UDPClientListener: listens for incomming UDP packets + */ +class UDPClientListener : public nsIUDPSocketListener +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIUDPSOCKETLISTENER + virtual ~UDPClientListener(); + nsresult mResult; +}; + +NS_IMPL_ISUPPORTS1(UDPClientListener, nsIUDPSocketListener) + +UDPClientListener::~UDPClientListener() +{ +} + +NS_IMETHODIMP +UDPClientListener::OnPacketReceived(nsIUDPSocket* socket, nsIUDPMessage* message) +{ + mResult = NS_OK; + + uint16_t port; + nsCString ip; + nsCOMPtr fromAddr; + message->GetFromAddr(getter_AddRefs(fromAddr)); + fromAddr->GetPort(&port); + fromAddr->GetAddress(ip); + passed("Packet received on client from %s:%d", ip.get(), port); + + if (TEST_SEND_API == phase && CheckMessageContent(message, REQUEST)) { + uint32_t count; + const uint32_t data = RESPONSE; + printf("*** Attempting to write response 0x%x to server by SendWithAddr...\n", RESPONSE); + mResult = socket->SendWithAddr(fromAddr, (const uint8_t*)&data, + sizeof(uint32_t), &count); + if (mResult == NS_OK && count == sizeof(uint32_t)) { + passed("Response written"); + } else { + fail("Response written"); + } + } else if (TEST_OUTPUT_STREAM != phase || !CheckMessageContent(message, RESPONSE)) { + mResult = NS_ERROR_FAILURE; + } + + // Notify thread + QuitPumpingEvents(); + return NS_OK; +} + +NS_IMETHODIMP +UDPClientListener::OnStopListening(nsIUDPSocket*, nsresult) +{ + QuitPumpingEvents(); + return NS_OK; +} + +/* + * UDPServerListener: listens for incomming UDP packets + */ +class UDPServerListener : public nsIUDPSocketListener +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIUDPSOCKETLISTENER + + virtual ~UDPServerListener(); + + nsresult mResult; +}; + +NS_IMPL_ISUPPORTS1(UDPServerListener, nsIUDPSocketListener) + +UDPServerListener::~UDPServerListener() +{ +} + +NS_IMETHODIMP +UDPServerListener::OnPacketReceived(nsIUDPSocket* socket, nsIUDPMessage* message) +{ + mResult = NS_OK; + + uint16_t port; + nsCString ip; + nsCOMPtr fromAddr; + message->GetFromAddr(getter_AddRefs(fromAddr)); + fromAddr->GetPort(&port); + fromAddr->GetAddress(ip); + passed("Packet received on server from %s:%d", ip.get(), port); + + if (TEST_OUTPUT_STREAM == phase && CheckMessageContent(message, REQUEST)) + { + nsCOMPtr outstream; + message->GetOutputStream(getter_AddRefs(outstream)); + + uint32_t count; + const uint32_t data = RESPONSE; + printf("*** Attempting to write response 0x%x to client by OutputStream...\n", RESPONSE); + mResult = outstream->Write((const char*)&data, sizeof(uint32_t), &count); + + if (mResult == NS_OK && count == sizeof(uint32_t)) { + passed("Response written"); + } else { + fail("Response written"); + } + } else if (TEST_SEND_API != phase || !CheckMessageContent(message, RESPONSE)) { + mResult = NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +UDPServerListener::OnStopListening(nsIUDPSocket*, nsresult) +{ + QuitPumpingEvents(); + return NS_OK; +} + +/**** Main ****/ +int +main(int32_t argc, char *argv[]) +{ + nsresult rv; + ScopedXPCOM xpcom("UDP ServerSocket"); + if (xpcom.failed()) + return -1; + + // Create UDPSocket + nsCOMPtr server, client; + server = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); + NS_ENSURE_SUCCESS(rv, -1); + client = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); + NS_ENSURE_SUCCESS(rv, -1); + + // Create UDPServerListener to process UDP packets + nsCOMPtr serverListener = new UDPServerListener(); + + // Bind server socket to 127.0.0.1 + rv = server->Init(0, true); + NS_ENSURE_SUCCESS(rv, -1); + int32_t serverPort; + server->GetPort(&serverPort); + server->AsyncListen(serverListener); + + // Bind clinet on arbitrary port + nsCOMPtr clientListener = new UDPClientListener(); + client->Init(0, true); + client->AsyncListen(clientListener); + + // Write data to server + uint32_t count; + const uint32_t data = REQUEST; + + phase = TEST_OUTPUT_STREAM; + rv = client->Send(NS_LITERAL_CSTRING("127.0.0.1"), serverPort, (uint8_t*)&data, sizeof(uint32_t), &count); + NS_ENSURE_SUCCESS(rv, -1); + REQUIRE_EQUAL(count, sizeof(uint32_t), "Error"); + passed("Request written by Send"); + + // Wait for server + PumpEvents(); + NS_ENSURE_SUCCESS(serverListener->mResult, -1); + + // Read response from server + NS_ENSURE_SUCCESS(clientListener->mResult, -1); + + mozilla::net::NetAddr clientAddr; + rv = client->GetAddress(&clientAddr); + NS_ENSURE_SUCCESS(rv, -1); + + phase = TEST_SEND_API; + rv = server->SendWithAddress(&clientAddr, (uint8_t*)&data, sizeof(uint32_t), &count); + NS_ENSURE_SUCCESS(rv, -1); + REQUIRE_EQUAL(count, sizeof(uint32_t), "Error"); + passed("Request written by SendWithAddress"); + + // Wait for server + PumpEvents(); + NS_ENSURE_SUCCESS(serverListener->mResult, -1); + + // Read response from server + NS_ENSURE_SUCCESS(clientListener->mResult, -1); + + // Close server + printf("*** Attempting to close server ...\n"); + server->Close(); + client->Close(); + PumpEvents(); + passed("Server closed"); + + return 0; // failure is a non-zero return +} diff --git a/netwerk/test/moz.build b/netwerk/test/moz.build index a72e73a4422..165f9a50b9c 100644 --- a/netwerk/test/moz.build +++ b/netwerk/test/moz.build @@ -53,6 +53,6 @@ SOURCES += [ CPP_UNIT_TESTS += [ 'TestSTSParser.cpp', - 'TestUDPServerSocket.cpp', + 'TestUDPSocket.cpp', ]