Bug 937528 - Initialize port and host for the tcp server accepted socket. r=jduell
authorHenry Chang <hchang@mozilla.com>
Thu, 19 Dec 2013 11:21:12 +0800
changeset 191946 5d4056c9923a68286593f704f00dc79c3fa72656
parent 191945 b6a20ba492e85711436a402ad7b5f71dedd20acf
child 191947 c3116313d9e1835d5fc30790d2d40028355d1977
push id27069
push userkwierso@gmail.com
push dateThu, 03 Jul 2014 00:00:48 +0000
treeherdermozilla-central@5d9af625f42e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs937528
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 937528 - Initialize port and host for the tcp server accepted socket. r=jduell
dom/network/interfaces/nsITCPSocketChild.idl
dom/network/interfaces/nsITCPSocketParent.idl
dom/network/src/TCPServerSocketParent.cpp
dom/network/src/TCPSocket.js
dom/network/src/TCPSocketChild.cpp
dom/network/src/TCPSocketChild.h
dom/network/src/TCPSocketParent.cpp
dom/network/tests/unit/test_tcpserversocket.js
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
--- a/dom/network/interfaces/nsITCPSocketChild.idl
+++ b/dom/network/interfaces/nsITCPSocketChild.idl
@@ -4,17 +4,17 @@
 
 #include "domstubs.idl"
 
 interface nsITCPSocketInternal;
 interface nsIDOMWindow;
 
 // Interface to allow the content process socket to reach the IPC bridge.
 // Implemented in C++ as TCPSocketChild, referenced as _socketBridge in TCPSocket.js
-[scriptable, uuid(292ebb3a-beac-4e06-88b0-b5b4e88ebd1c)]
+[scriptable, uuid(4277aff0-4c33-11e3-8f96-0800200c9a66)]
 interface nsITCPSocketChild : nsISupports
 {
   // Tell the chrome process to open a corresponding connection with the given parameters
   [implicit_jscontext]
   void sendOpen(in nsITCPSocketInternal socket, in DOMString host,
                 in unsigned short port, in boolean ssl, in DOMString binaryType,
                 in nsIDOMWindow window, in jsval windowVal);
 
@@ -39,9 +39,12 @@ interface nsITCPSocketChild : nsISupport
    *        The TCP socket on the child side.
    *        This instance is connected with the child IPC side of the IPC bridge.
    * @param windowVal
    *        The window object on the child side to create data
    *        as "jsval" for deserialization.
    */
   [implicit_jscontext]
   void setSocketAndWindow(in nsITCPSocketInternal socket, in jsval windowVal);
+
+  readonly attribute DOMString host;
+  readonly attribute unsigned short port;
 };
--- a/dom/network/interfaces/nsITCPSocketParent.idl
+++ b/dom/network/interfaces/nsITCPSocketParent.idl
@@ -7,17 +7,17 @@
 interface nsIDOMTCPSocket;
 interface nsIDOMTCPServerSocket;
 interface nsITCPServerSocketParent;
 interface nsITCPSocketIntermediary;
 
 // Interface required to allow the TCP socket object (TCPSocket.js) in the
 // parent process to talk to the parent IPC actor, TCPSocketParent, which
 // is written in C++.
-[scriptable, uuid(868662a4-681c-4b89-9f02-6fe5b7ace265)]
+[scriptable, uuid(6f040bf0-6852-11e3-949a-0800200c9a66)]
 interface nsITCPSocketParent : nsISupports
 {
   [implicit_jscontext] void initJS(in jsval intermediary);
 
   // Trigger a callback in the content process for |type|, providing a serialized
   // argument of |data|, and update the child's readyState value with the given
   // values.
   //
@@ -50,16 +50,19 @@ interface nsITCPSocketParent : nsISuppor
   //        The new value of bufferedAmount that is going to be set to child's
   //        bufferedAmount.
   // @param trackingNumber
   //        Parent's current tracking number, reflecting the number of calls to
   //        send() on the child process. This number is sent back to the child
   //        to make sure the bufferedAmount updated on the child will correspond
   //        to the latest call of send().
   void sendUpdateBufferedAmount(in uint32_t bufferedAmount, in uint32_t trackingNumber);
+
+  readonly attribute DOMString host;
+  readonly attribute unsigned short port;
 };
 
 // Intermediate class to handle sending multiple possible data types
 // and kicking off the chrome process socket object's connection.
 // This interface is the bridge of TCPSocketParent, which is written in C++,
 // and TCPSocket, which is written in Javascript. TCPSocketParentIntermediary
 // implements nsITCPSocketIntermediary in Javascript.
 [scriptable, uuid(c434224a-dbb7-4869-8b2b-e49cee990e85)]
--- a/dom/network/src/TCPServerSocketParent.cpp
+++ b/dom/network/src/TCPServerSocketParent.cpp
@@ -69,18 +69,34 @@ TCPServerSocketParent::Init(PNeckoParent
 NS_IMETHODIMP
 TCPServerSocketParent::SendCallbackAccept(nsITCPSocketParent *socket)
 {
   TCPSocketParent* _socket = static_cast<TCPSocketParent*>(socket);
   PTCPSocketParent* _psocket = static_cast<PTCPSocketParent*>(_socket);
 
   _socket->AddIPDLReference();
 
+  nsresult rv;
+
+  nsString host;
+  rv = socket->GetHost(host);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Failed to get host from nsITCPSocketParent");
+    return NS_ERROR_FAILURE;
+  }
+
+  uint16_t port;
+  rv = socket->GetPort(&port);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Failed to get port from nsITCPSocketParent");
+    return NS_ERROR_FAILURE;
+  }
+
   if (mNeckoParent) {
-    if (mNeckoParent->SendPTCPSocketConstructor(_psocket)) {
+    if (mNeckoParent->SendPTCPSocketConstructor(_psocket, host, port)) {
       mozilla::unused << PTCPServerSocketParent::SendCallbackAccept(_psocket);
     }
     else {
       NS_ERROR("Sending data from PTCPSocketParent was failed.");
     };
   }
   else {
     NS_ERROR("The member value for NeckoParent is wrong.");
--- a/dom/network/src/TCPSocket.js
+++ b/dom/network/src/TCPSocket.js
@@ -432,27 +432,33 @@ TCPSocket.prototype = {
     that._transport = transport;
     that._initStream(binaryType);
 
     // ReadyState is kOpen since accepted transport stream has already been connected
     that._readyState = kOPEN;
     that._inputStreamPump = new InputStreamPump(that._socketInputStream, -1, -1, 0, 0, false);
     that._inputStreamPump.asyncRead(that, null);
 
+    // Grab host/port from SocketTransport.
+    that._host = transport.host;
+    that._port = transport.port;
+
     return that;
   },
 
   createAcceptedChild: function ts_createAcceptedChild(socketChild, binaryType, windowObject) {
     let that = new TCPSocket();
 
     that._binaryType = binaryType;
     that._inChild = true;
     that._readyState = kOPEN;
     socketChild.setSocketAndWindow(that, windowObject);
     that._socketBridge = socketChild;
+    that._host = socketChild.host;
+    that._port = socketChild.port;
 
     return that;
   },
 
   setAppId: function ts_setAppId(appId) {
 #ifdef MOZ_WIDGET_GONK
     this._appId = appId;
 #else
--- a/dom/network/src/TCPSocketChild.cpp
+++ b/dom/network/src/TCPSocketChild.cpp
@@ -68,35 +68,42 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
     PTCPSocketChild::SendRequestDelete();
     return 1;
   }
   return refcnt;
 }
 
 TCPSocketChild::TCPSocketChild()
 : mWindowObj(nullptr)
+, mHost()
+, mPort(0)
 {
 }
 
+void TCPSocketChild::Init(const nsString& aHost, const uint16_t& aPort) {
+  mHost = aHost;
+  mPort = aPort;
+}
+
 NS_IMETHODIMP
 TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
                          const nsAString& aHost, uint16_t aPort,
                          bool aUseSSL, const nsAString& aBinaryType,
                          nsIDOMWindow* aWindow, JS::Handle<JS::Value> aWindowObj,
                          JSContext* aCx)
 {
   mSocket = aSocket;
 
   MOZ_ASSERT(aWindowObj.isObject());
   mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
   if (!mWindowObj) {
     return NS_ERROR_FAILURE;
   }
   AddIPDLReference();
-  gNeckoChild->SendPTCPSocketConstructor(this);
+  gNeckoChild->SendPTCPSocketConstructor(this, nsString(aHost), aPort);
   PTCPSocketChild::SendOpen(nsString(aHost), aPort,
                             aUseSSL, nsString(aBinaryType));
   return NS_OK;
 }
 
 void
 TCPSocketChildBase::ReleaseIPDLReference()
 {
@@ -241,16 +248,30 @@ TCPSocketChild::SetSocketAndWindow(nsITC
   MOZ_ASSERT(aWindowObj.isObject());
   mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
   if (!mWindowObj) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+TCPSocketChild::GetHost(nsAString& aHost)
+{
+  aHost = mHost;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TCPSocketChild::GetPort(uint16_t* aPort)
+{
+  *aPort = mPort;
+  return NS_OK;
+}
+
 bool
 TCPSocketChild::RecvRequestDelete()
 {
   mozilla::unused << Send__delete__(this);
   return true;
 }
 
 } // namespace dom
--- a/dom/network/src/TCPSocketChild.h
+++ b/dom/network/src/TCPSocketChild.h
@@ -40,22 +40,26 @@ class TCPSocketChild : public mozilla::n
 {
 public:
   NS_DECL_NSITCPSOCKETCHILD
   NS_IMETHOD_(MozExternalRefCountType) Release() MOZ_OVERRIDE;
 
   TCPSocketChild();
   ~TCPSocketChild();
 
+  void Init(const nsString& aHost, const uint16_t& aPort);
+
   virtual bool RecvCallback(const nsString& aType,
                             const CallbackData& aData,
                             const nsString& aReadyState) MOZ_OVERRIDE;
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
   virtual bool RecvUpdateBufferedAmount(const uint32_t& aBufferred,
                                         const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
 private:
   JSObject* mWindowObj;
+  nsString mHost;
+  uint16_t mPort;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/network/src/TCPSocketParent.cpp
+++ b/dom/network/src/TCPSocketParent.cpp
@@ -273,16 +273,36 @@ NS_IMETHODIMP
 TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount,
                                           uint32_t aTrackingNumber)
 {
   mozilla::unused << PTCPSocketParent::SendUpdateBufferedAmount(aBufferedAmount,
                                                                 aTrackingNumber);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+TCPSocketParent::GetHost(nsAString& aHost)
+{
+  if (!mSocket) {
+    NS_ERROR("No internal socket instance mSocket!");
+    return NS_ERROR_FAILURE;
+  }
+  return mSocket->GetHost(aHost);
+}
+
+NS_IMETHODIMP
+TCPSocketParent::GetPort(uint16_t* aPort)
+{
+  if (!mSocket) {
+    NS_ERROR("No internal socket instance mSocket!");
+    return NS_ERROR_FAILURE;
+  }
+  return mSocket->GetPort(aPort);
+}
+
 void
 TCPSocketParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mSocket) {
     mSocket->Close();
   }
   mSocket = nullptr;
   mIntermediaryObj = nullptr;
--- a/dom/network/tests/unit/test_tcpserversocket.js
+++ b/dom/network/tests/unit/test_tcpserversocket.js
@@ -169,40 +169,48 @@ function connectSock() {
     server.close();
   }
 
   var yayFuncs = makeJointSuccess(['serveropen', 'clientopen']);
   var options = { binaryType: 'arraybuffer' };
 
   server = TCPSocket.listen(PORT, options, BACKLOG);
   server.onconnect = function(socket) {
+    // Bug 937528 - Accepted client tcp socket (mozTcpSocket) has
+    //              uninitialized host and port.
+    if (socket.host !== '127.0.0.1') {
+      do_throw('got unexpected: connected socket host should be 127.0.0.1 but not ' + socket.host);
+    } else {
+      do_print('Got expected connected socket host: ' + socket.host);
+    }
+
     connectedsock = socket;
     connectedsock.ondata = makeFailureCase('serverdata');
     connectedsock.onerror = makeFailureCase('servererror');
     connectedsock.onclose = makeFailureCase('serverclose');
     yayFuncs.serveropen();
   };
   server.onerror = makeFailureCase('error');
   sock = TCPSocket.open(
     '127.0.0.1', PORT, options);
   sock.onopen = yayFuncs.clientopen;
   sock.ondrain = null;
   sock.ondata = makeFailureCase('data');
   sock.onerror = makeFailureCase('error');
-  sock.onclose = makeFailureCase('close');  
+  sock.onclose = makeFailureCase('close');
 }
 
 /**
  * Connect the socket to the server after the server was closed.
  * This test is added after test to close the server was conducted.
  */
 function openSockInClosingServer() {
   var success = makeSuccessCase('clientnotopen');
   var options = { binaryType: 'arraybuffer' };
-  
+
   sock = TCPSocket.open(
     '127.0.0.1', PORT, options);
 
   sock.onopen = makeFailureCase('open');
   sock.onerror = success;
 }
 
 /**
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -196,19 +196,21 @@ NeckoChild::DeallocPRtspChannelChild(PRt
 #ifdef NECKO_PROTOCOL_rtsp
   RtspChannelChild* p = static_cast<RtspChannelChild*>(child);
   p->ReleaseIPDLReference();
 #endif
   return true;
 }
 
 PTCPSocketChild*
-NeckoChild::AllocPTCPSocketChild()
+NeckoChild::AllocPTCPSocketChild(const nsString& host,
+                                 const uint16_t& port)
 {
   TCPSocketChild* p = new TCPSocketChild();
+  p->Init(host, port);
   p->AddIPDLReference();
   return p;
 }
 
 bool
 NeckoChild::DeallocPTCPSocketChild(PTCPSocketChild* child)
 {
   TCPSocketChild* p = static_cast<TCPSocketChild*>(child);
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -38,17 +38,18 @@ protected:
     AllocPFTPChannelChild(const PBrowserOrId& aBrowser,
                           const SerializedLoadContext& aSerialized,
                           const FTPChannelCreationArgs& aOpenArgs) MOZ_OVERRIDE;
   virtual bool DeallocPFTPChannelChild(PFTPChannelChild*) MOZ_OVERRIDE;
   virtual PWebSocketChild*
     AllocPWebSocketChild(const PBrowserOrId&,
                          const SerializedLoadContext&) MOZ_OVERRIDE;
   virtual bool DeallocPWebSocketChild(PWebSocketChild*) MOZ_OVERRIDE;
-  virtual PTCPSocketChild* AllocPTCPSocketChild() MOZ_OVERRIDE;
+  virtual PTCPSocketChild* AllocPTCPSocketChild(const nsString& host,
+                                                const uint16_t& port) MOZ_OVERRIDE;
   virtual bool DeallocPTCPSocketChild(PTCPSocketChild*) MOZ_OVERRIDE;
   virtual PTCPServerSocketChild*
     AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
                                const uint16_t& aBacklog,
                                const nsString& aBinaryType) MOZ_OVERRIDE;
   virtual bool DeallocPTCPServerSocketChild(PTCPServerSocketChild*) MOZ_OVERRIDE;
   virtual PUDPSocketChild* AllocPUDPSocketChild(const nsCString& aHost,
                                                 const uint16_t& aPort,
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -392,18 +392,22 @@ NeckoParent::DeallocPRtspChannelParent(P
 #ifdef NECKO_PROTOCOL_rtsp
   RtspChannelParent* p = static_cast<RtspChannelParent*>(actor);
   p->Release();
 #endif
   return true;
 }
 
 PTCPSocketParent*
-NeckoParent::AllocPTCPSocketParent()
+NeckoParent::AllocPTCPSocketParent(const nsString& /* host */,
+                                   const uint16_t& /* port */)
 {
+  // We actually don't need host/port to construct a TCPSocketParent since
+  // TCPSocketParent will maintain an internal nsIDOMTCPSocket instance which
+  // can be delegated to get the host/port. 
   TCPSocketParent* p = new TCPSocketParent();
   p->AddIPDLReference();
   return p;
 }
 
 bool
 NeckoParent::DeallocPTCPSocketParent(PTCPSocketParent* actor)
 {
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -122,17 +122,18 @@ protected:
                       const PBrowserOrId& aBrowser,
                       const SerializedLoadContext& aSerialized,
                       const FTPChannelCreationArgs& aOpenArgs) MOZ_OVERRIDE;
   virtual bool DeallocPFTPChannelParent(PFTPChannelParent*) MOZ_OVERRIDE;
   virtual PWebSocketParent*
     AllocPWebSocketParent(const PBrowserOrId& browser,
                           const SerializedLoadContext& aSerialized) MOZ_OVERRIDE;
   virtual bool DeallocPWebSocketParent(PWebSocketParent*) MOZ_OVERRIDE;
-  virtual PTCPSocketParent* AllocPTCPSocketParent() MOZ_OVERRIDE;
+  virtual PTCPSocketParent* AllocPTCPSocketParent(const nsString& host,
+                                                  const uint16_t& port) MOZ_OVERRIDE;
 
   virtual PRemoteOpenFileParent*
     AllocPRemoteOpenFileParent(const SerializedLoadContext& aSerialized,
                                const URIParams& aFileURI,
                                const OptionalURIParams& aAppURI) MOZ_OVERRIDE;
   virtual bool
     RecvPRemoteOpenFileConstructor(PRemoteOpenFileParent* aActor,
                                    const SerializedLoadContext& aSerialized,
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -97,14 +97,17 @@ child:
    * Bring up the http auth prompt for a nested remote mozbrowser.
    * NestedFrameId is the id corresponding to the PBrowser.  It is the same id
    * that was passed to the PBrowserOrId param in to the PHttpChannel constructor
    */
   AsyncAuthPromptForNestedFrame(uint64_t nestedFrameId, nsCString uri,
                                 nsString realm, uint64_t callbackId);
 
 both:
-  PTCPSocket();
+  // Actually we need PTCPSocket() for parent. But ipdl disallows us having different
+  // signatures on parent and child. So when constructing the parent side object, we just 
+  // leave host/port unused.
+  PTCPSocket(nsString host, uint16_t port);
 };
 
 
 } // namespace net
 } // namespace mozilla