This API provides interfaces to raw UDP sockets, TCP Client sockets and TCP Server sockets.

This specification is based the Streams API, [[!STREAMS]]. Note that the Streams API is work in progress and any changes made to Streams may impact the TCP and UDP Socket API specification. However, it is the editor's ambition to continously update the TCP and UDP API specification to be aligned with the latest version the Streams API.

This is a note on error handling.

When using promises rejection reasons should always be instances of the ECMAScript Error type such as DOMException or the built in ECMAScript error types. See Promise rejection reasons. In the TCP and UDP Socket API the error names defined in WebIDL Exceptions are used. If additional error names are needed an update to Github WebIDL should be requested through a Pull Request.

This is a note on data types of TCP and UDP to send and receive.

In the previous version of this API the send() method accepted the following data types for the data to send: DOMString,Blob, ArrayBuffer or ArrayBufferView. This was aligned with the send() method for Web Sockets. In this Streams API based version only ArrayBuffer is accepted as type for data to send. The reason is that encoding issues in a Streams based API should instead be handled by a transform stream.

Introduction

Use this API to send and receive data over the network using TCP or UDP.

Examples of use cases for this API are:

This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.

Implementations that use ECMAScript to implement the APIs defined in this specification MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]], as this specification uses that specification and terminology.

Terminology

The Promise interface provides asynchronous access to the result of an operation that is ongoing, has yet to start, or has completed, as defined in [[!ES6]].

Security and privacy considerations

This API must be only exposed to trusted content.

There is ongoing work on trust and permissions in W3C. For example see Workshop on trust and permissions for Web applications 3–4 September 2014, Paris, France. The assumption is that this API must only be exposed to trusted content according to a security model based on existing web security mechanisms such as tls/ssl, signed manifests, csp, etc. The details of that security model as such is out of scope for this specification as this model should apply to any security and privacy sensitive API.

Interface UDPSocket

The UDPSocket interface defines attributes and methods for UDP communication

 
        // 
        // This example shows a simple implementation of UPnP-SSDP M-SEARCH
        // discovery using a multicast UDPSocket 
        //
      
        var address = '239.255.255.250',
            port = '1900',
            serviceType = 'upnp:rootdevice',
            rn = '\r\n',
            search = '';
        
        //  Create a new UDP client socket
        var mySocket = new UDPSocket();
        
        // Build an SSDP M-SEARCH multicast message
        search += 'M-SEARCH * HTTP/1.1' + rn;
        search += 'ST: ' + serviceType + rn;
        search += 'MAN: "ssdp:discover"' + rn;
        search += 'HOST: ' + address + ':' + port + rn;
        search += 'MX: 10';
        
        
        // Receive and log SSDP M-SEARCH response messages
        function receiveMSearchResponses() {         
        
          // While data in buffer, read and log UDP message
          while (mySocket.readable.state === "readable") {            
            var msg = mySocket.readable.read();
            console.log ('Remote address: ' + msg.remoteAddress + 
                         ' Remote port: ' + msg.remotePort + 
                         'Message: ' + ab2str(msg.data)); 
              // ArrayBuffer to string conversion could also be done by piping 
              // through a transform stream. To be updated when the Streams API
              // specification has been stabilized on this point. 
          }  
              
          // Wait for SSDP M-SEARCH responses to arrive     
          mySocket.readable.wait().then(
            receiveMSearchResponses,          
            e => console.error("Receiving error: ", e);
          );     
        }
        
        // Join SSDP multicast group
        mySocket.joinMulticast(address);
        
        // Send SSDP M-SEARCH multicast message
        mySocket.writeable.write(
          {data : str2ab(search),
           remoteAddress : address,
           remotePort : port
          }).then(
            () => {
              // Data sent sucessfully, wait for response
              console.log('M-SEARCH Sent');
              receiveMSearchResponses();
            },
            e => console.error("Sending error: ", e);
        );
        
        // Log result of UDP socket setup. 
        mySocket.opened.then(
          () => {
            console.log("UDP socket created sucessfully");
          },
          e =>console.error("UDP socket setup failed due to error: ", e);
        );
        
        // Handle UDP socket closed, either as a result of the application 
        // calling mySocket.close() or an error causing the socket to be 
           closed.
        mySocket.closed.then(
          () => {
             console.log("Socket has been cleanly closed");
          },
          e => console.error("Socket closed due to error: ", e);
        );          

      
readonly attribute DOMString? localAddress
The IPv4/6 address of the local interface, e.g. wifi or 3G, that the UDPSocket object is bound to. Can be set by the constructor's options argument's localAddress member. If this member is not present but the remoteAddress member is present, the user agent binds the socket to a local IPv4/6 address based on the routing table and possiby a preselect default local interface to use for the selected remoteAddress. Else, i.e. neither the localAddress or the remoteAddress members are present in the constructor's options argument, the localAddress attribute is set to null.
readonly attribute unsigned short? localPort
The local port that the UDPSocket object is bound to. Can be set by the options argument in the constructor. If not set the user agent binds the socket to an ephemeral local port decided by the system and this attribute is null.
readonly attribute DOMString? remoteAddress
The default remote host name or IPv4/6 address that is used for subsequent send() calls. Null if not stated by the options argument of the constructor.
readonly attribute unsigned short? remotePort
The default remote port that is used for subsequent send() calls. Null if not stated by the options argument of the constructor
readonly attribute boolean addressReuse
true allows the socket to be bound to a local address/port pair that already is in use. Can be set by the options argument in the constructor. Default is true.
readonly attribute boolean loopback
Only applicable for multicast. true means that sent multicast data is looped back to the sender. Can be set by the options argument in the constructor. Default is false.
readonly attribute SocketReadyState readyState
The state of the UDP Socket object. A UDP Socket object can be in "open" "opening" or "closed" states. See enum SocketReadyState for details.
readonly attribute Promise opened
Detects the result of the UDP socket creation attempt. Returns the openedPromise that was created in the UDPSocket constructor.
readonly attribute Promise closed
Detects when the UDP socket has been closed, either cleanly by the client application calling close()) or through an error situation, e.g. network contact lost. Returns the closedPromise that was created in the UDPSocket constructor.
readonly attribute ReadableStream readable
The object that represents the UDP socket's source of data, from which you can read. [[!STREAMS]]
readonly attribute WriteableStream writeable
The object that represents the UDP socket's destination for data, into which you can write. [[!STREAMS]]
Promise close()

Closes the UDP socket. Returns the closedPromise that was created in the UDPSocket constructor.

void joinMulticast()

Joins a multicast group identified by the given address.

Note that even if the socket is only sending to a multicast address, it is a good practice to explicitely join the multicast group (otherwise some routers may not relay packets).

DOMString multicastGroupAddress
The multicast group address.
void leaveMulticast()

Leaves a multicast group membership identified by the given address.

DOMString multicastGroupAddress
The multicast group address.

When the UDPSocket constructor is invoked, the User Agent MUST run the following steps:

  1. Create a new UDPSocket object ("mySocket").
  2. If the options argument's remoteAddress member is present and it is a valid host name or IPv4/6 address then set the mySocket.remoteAddress attribute (default remote address) to the requested address. Else, if the remoteAddress member is present but it is not a valid host name or IPv4/6 address then throw DOMException InvalidAccessError and abort the remaining steps. Otherwise, if the options argument's remoteAddress member is absent then set the mySocket.remoteAddress attribute (default remote address) to null.
  3. If the options argument's remotePort member is present and it is a valid port number then set the mySocket.remotePort attribute (default remote port) to the requested port. Else, if the remotePort member is present but it is not a valid port number then throw DOMException InvalidAccessError and abort the remaining steps. Otherwise, if the options argument's remotePort member is absent then set the mySocket.remotePort attribute (default port number) to null.
  4. If the options argument's localAddress member is present and the options argument's remoteAddress member is present, execute the following step:
    • If the options argument's localAddress member is a valid IPv4/6 address for a local interface that can be used to connect to the selected remoteAddress (according to the routing table) bind the socket to this local IPv4/6 address and set the mySocket.localAddress attribute to this addres. Else, if the localAddress member is present but it is not a valid local IPv4/6 address for a local interface that can be used to connect to the selected remoteAddress, throw DOMException InvalidAccessError and abort the remaining steps.
    Else, if the options argument's localAddress member is present and the options argument's remoteAddress member is absent, execute the following step:
    • If the options argument's localAddress member is a valid IPv4/6 address for a local interface on the device bind the socket to this local IPv4/6 address and set the mySocket.localAddress attribute to this addres. Else, if the localAddress member is present but it is not a valid local IPv4/6 address for a local interface on the device, throw DOMException InvalidAccessError and abort the remaining steps. Note that binding the UDPSocket to a certain local interface means that the socket can only be used to send UDP datagrams to peers reachable through this local interface.
    Else, if the options argument's localAddress member is absent, and the options argument's remoteAddress member is present, execute the following steps:
    1. Use the routing table to determine the local interface(s) that can be used to send datagrams to the selected remoteAddress. If no local interface can be used to send datagrams to the selected remoteAddress, throw DOMException InvalidAccessError and abort the remaining steps.
    2. If the routing table states that more than one local interface can be used to send datagrams to the selected remoteAddress bind the socket to the IPv4/6 address of the "default" local interface to use for the selected remoteAddress. The selection of a "default" local interface is out of scope for this specification.
    3. Set the mySocket.localAddress attribute to the local address that the socket is bound to.
    Else, i.e. the options argument's localAddress member is absent, and the options argument's remoteAddress member is absent, execute the following step:
    • Set the mySocket.localAddress attribute to null.
  5. If the options argument's localPort member is absent then bind the socket to an ephemeral local port decided by the system and set the mySocket.localPort attribute to null. Otherwise, bind the socket to the requested local port and set the mySocket.localPort attribute to the local port that the socket is bound to.
  6. Set the mySocket.addressReuse attribute to the value of the options argument's addressReuse member if it is present or to true if the options argument's addressReuse member is not present.
  7. If the options argument's loopback member is present then set the mySocket.loopback attribute to the value of this field. Else set this attribute to false.
  8. Set the mySocket.readyState attribute to "opening".
  9. Create a new promise, "openedPromise", and store it so it can later be returned by the opened property.
  10. Create a new promise, "closedPromise", and store it so it can later be returned by the closed property and the close method.
  11. Let the mySocket.readable attribute be a new ReadableStream object, [[!STREAMS]]. The User Agent MUST implement the adaptation layer to [[!STREAMS]] for this new ReadableStream object through implementation of a number of functions that are given as input arguments to the constructor and called by the [[!STREAMS]] implementation. The semantics for these functions are described below:
    • The constructor's start() function is called immediately by the [[!STREAMS]] implementation. The start() function MUST run the following steps:
      1. Setup the UDP socket to the bound local and remote address/port pairs in the background (without blocking scripts) and return openedPromise.
      2. When the UDP socket has been successfully setup the following steps MUST run:
        1. Change the mySocket.readyState attribute's value to "open".
        2. Resolve openedPromise with undefined.
      The following internal methods of the ReadableStream are arguments of the constructor's start() function and MUST be called by the start() function implementation according to the following steps:
      • The enqueue() argument of start() is a function that pushes received data into the internal buffer.
        When a new UDP datagram has been received the following steps MUST run:
        1. Create a new instance of UDPMessage.
        2. Set the UDPMessage object's data member to a new read-only ArrayBuffer object whose contents are the received UDP datagram [[!TYPED-ARRAYS]].
        3. Set the remoteAddress member of the UDPMessage object to the source address of the received UDP datagram.
        4. Set the remotePort member of the UDPMessage object to the source port of the received UDP datagram.
        5. Call enqueue() to push the UDPMessage object into the internal [[!STREAMS]] receive buffer. Note that enqueue() returns false if the high watermark of the buffer is reached. However, as there is no flow control mechanism in UDP the flow of datagrams can't be stopped. The enqueue() return value should therefore be ignored. This means that datagrams will be lost if the internal receive buffer has been filled to it's memory limit but this is the nature of an unreliable protocol as UDP.
      • The error() argument of start() is a function that handles readable stream errors and closes the readble stream.
        Upon detection that the attempt to setup a new UDP socket (mySocket.readyState is "opening") has failed, e.g. because the local address/port pair is already in use and mySocket.addressReuse is false, the following steps MUST run:
        1. Call error() with DOMException "NetworkError".
        2. Reject openedPromise with DOMException "NetworkError".
        3. Reject closedPromise with DOMException "NetworkError".
        4. Change the mySocket.readyState attribute's value to "closed" and release any underlying resources associated with this socket.
        Upon detection that there is an error with the established UDP socket (mySocket.readyState is "open"), e.g. network connection is lost, the following steps MUST run:
        1. Call error() with DOMException "NetworkError".
        2. Reject closedPromise with DOMException "NetworkError".
        3. Change the mySocket.readyState attribute's value to "closed" and release any underlying resources associated with this socket.
        When a new UDP datagram has been received and upon detction that it is not possible to convert the received UDP data to ArrayBuffer, [[!TYPED-ARRAYS]], the following steps MUST run:
        1. Call error() with TypeError.
        2. Reject closedPromise with TypeError.
        3. Change the mySocket.readyState attribute's value to "closed" and release any underlying resources associated with this socket.
    • The constructor's pull() function MUST be omitted as there is no flow control mechanism in UDP and the flow of datagrams cannot be stopped and started again.
    • The constructor's cancel() function input argument is called by the [[!STREAMS]] implementation when the ReadbleStream should be canceled. For UDP this means that the UDP socket should be closed for reading and writing. The cancel() function MUST run the following steps:
      1. If mySocket.readyState is "closed" then do nothing and abort the remaning steps.
      2. If mySocket.readyState is "opening" then fail the UDP socket setup process, reject openedPromise with DOMException AbortError and set the mySocket.readyState attribute to "closed".
      3. If mySocket.readyState is "open" the the following steps MUST run:
        1. Call mySocket.writeable.close() to assure that any buffered send data is sent.
        2. Set the mySocket.readyState attribute's value to "closed".
        3. Resolve closedPromise with undefined and release any underlying resources associated with this socket.

      If the constructor's strategy argument is omitted the Default strategy for Readable Streams applies. Currently this means that the ReadableStream object goes to "readable" state after 1 chunk has been enqueued to the internal ReadableStream object's input buffer. An application should call .wait() to be notified when the state changes to "readable". To be further investigated which ReadableStreamStrategy that should be applied to UDP.

  12. Let the mySocket.writeable attribute be a new WritableStream object, [[!STREAMS]]. The User Agent MUST implement the adaptation layer to [[!STREAMS]] for this new WritableStream object through implementation of a number of functions that are given as input arguments to the constructor and called by the [[!STREAMS]] implementation. The semantics for these functions are described below:
    • The constructor's start() function MUST run the following steps:
      1. Create a new promise, "writableStartPromise".
      2. If the attempt to create a new UDP socket (see the description of the semantics for the mySocket.readable attribute constructor's start() function ) succeded resolve writableStartPromise with undefined, else reject writableStartPromise with DOMException "NetworkError".
    • The constructor's write(chunk) function is called by the [[!STREAMS]] implementation to write UDP data. The write() function MUST run the following steps:
      1. Create a new promise, "writePromise"
      2. Convert the chunk argument to a UDPMessage object (per [[!WEBIDL]] dictionary conversion).
      3. If no default remote address was specified in the UDPSocket's constructor options argument's remoteAddress member and the UDPMessage object's remoteAddress member is not present or null then throw DOMException InvalidAccessError and abort these steps.
      4. If no default remote port was specified in the UDPSocket's constructor options argument's remotePort member and the UDPMessage object's remotePort member is not present or null then throw DOMException InvalidAccessError and abort these steps.
      5. Send UDP data with data passed in the data member of the UDPMessage object. The destination address is the address defined by the UDPMesssage object's remoteAddress member if present, else the destination address is defined by the UDPSocket's constructor options argument's remoteAddress member. The destination port is the port defined by the UDPMesssage object's remotePort member if present, else the destination port is defined by the UDPSocket's constructor options argument's remotePort member.
      6. If sending succeed resolve writePromise with undefined, else reject writePromise with DOMException "NetworkError".
    • The constructor's close() and abort() functions MUST be omitted as it is not possible to just close the writable side of a UDP socket.

      If the constructor's strategy argument is omitted the Default strategy for Writable Streams applies. Currently this means that the WriteableStream object goes to "waiting" state after 1 chunk has been written to the internal WriteableStream object's output buffer. This means that the application should call .wait() to be notified of when the state changes to "writable", i.e. the queued chunk has been written to the remote peer and more data chunks could be written. To be further investigated which WritableStreamStrategy that should be applied to UDP.

  13. Return the newly created UDPSocket object ("mySocket") to the application.

The close method when invoked MUST run the following steps:

  1. Call mysocket.readable.cancel(reason). (Reason codes TBD.)
  2. Return closedPromise.

Interface TCPSocket

The TCPSocket interface defines attributes and methods for TCP communication

       // 
       // This example shows a simple TCP echo client. 
       // The client will send "Hello World" to the server on port 6789 and log 
       // what has been received from the server.
       //   
       
       //  Create a new TCP client socket and connect to remote host     
       var mySocket = new TCPSocket("127.0.0.1", 6789);
       
       // Send data to server
       mySocket.writeable.write("Hello World").then(
           () => {
               
               // Data sent sucessfully, wait for response
               console.log("Data has been sent to server");
               mySocket.readable.wait().then(
                   () => {
                   
                       // Data in buffer, read it
                       console.log("Data received from server:" + mySocket.readable.read());
       
                       // Close the TCP connection
                       mySocket.close();
                   },
                    
                   e => console.error("Receiving error: ", e);
               );
           },
           e => console.error("Sending error: ", e);
       );
       
       // Signal that we won't be writing any more and can close the write half of the connection.
       mySocket.halfClose();

       // Log result of TCP connection attempt. 
       mySocket.opened.then(
         () => {
           console.log("TCP connection established sucessfully");
         },
         e =>console.error("TCP connection setup failed due to error: ", e);
       );
       
       // Handle TCP connection closed, either as a result of the application 
       // calling mySocket.close() or the other side closed the TCP  
       // connection or an error causing the TCP connection to be closed.
       mySocket.closed.then(
         () => {
            console.log("TCP socket has been cleanly closed");
         },
         e => console.error("TCP socket closed due to error: ", e);
       );
        
      
readonly attribute DOMString remoteAddress
The host name or IPv4/6 address of the peer as stated by the remoteAddress argument in the constructor.
readonly attribute unsigned short remotePort
The port of the peer as stated by the remotePort argument in the constructor.
readonly attribute DOMString localAddress
The IPv4/6 address of the local interface, e.g. wifi or 3G, that the TCPSocket object is bound to. Can be set by the options argument in the constructor. If not set the user agent binds the socket to an IPv4/6 address based on the routing table and possibly a preselect default local interface to use for the selected remoteAddress.
readonly attribute unsigned short localPort
The local port that the TCPSocket object is bound to. Can be set by the options argument in the constructor. If not set the user agent binds the socket to an ephemeral local port decided by the system.
readonly attribute boolean addressReuse
true allows the socket to be bound to a local address/port pair that already is in use. Can be set by the options argument in the constructor. Default is true.
readonly attribute boolean noDelay
true if the Nagle algorithm for send coalescing, [[!NAGLE]], is disabled. Can be set by the options argument in the constructor. Default is true.
readonly attribute SocketReadyState readyState
The state of the TCP Socket object. See enum SocketReadyState for details.
readonly attribute Promise opened
Detects the result of the TCP connection attempt with the remote peer. Returns the openedPromise that was created in the TCPSocket constructor.
readonly attribute Promise closed
Detects when the TCP connection has been closed, either cleanly (initiated either by the server, or by the client application calling close()) or through an error situation. Returns the closedPromise that was created in the TCPSocket constructor.
readonly attribute ReadableStream readable
The object that represents the TCP socket's source of data, from which you can read. [[!STREAMS]]
readonly attribute WriteableStream writeable
The object that represents the TCP socket's destination for data, into which you can write. [[!STREAMS]]
Promise close()

Closes the TCP socket. Returns the closedPromise that was created in the TCPSocket constructor.

void halfClose()

Half closes the TCP socket.

When the TCPSocket constructor is invoked, the User Agent MUST run the following steps:

  1. Create a new TCPSocket object ("mySocket").
  2. If the remoteAddress argument is not a valid host name or IPv4/6 address and/or the remotePort argument is not a valid port number then throw DOMException "InvalidAccessError" and abort the remaining steps, else set the mySocket.remoteAddress and mySocket.remotePort attributes to the requested values.
  3. If the options argument's localAddress member is present and it is a valid IPv4/6 address for a local interface that can be used to connect to the selected remoteAddress (according to the routing table) bind the socket to this local IPv4/6 address and set the mySocket.localAddress attribute to this addres. Else, if the localAddress member is present but it is not a valid local IPv4/6 address for a local interface that can be used to connect to the selected remoteAddress then throw DOMException "InvalidAccessError" and abort the remaining steps.
    Otherwise, if the options argument's localAddress member is absent, execute the following steps:
    1. Use the routing table to determine the local interface(s) that can be used to connect to the selected remoteAddress. If no local interface can be used to connect to the selected remoteAddress then throw DOMException "InvalidAccessError" and abort the remaining steps.
    2. If the routing table states that more than one local interface can be used to connect to the selected remoteAddress bind the socket to the IPv4/6 address of the "default" local interface to use for the selected remoteAddress. The selection of a "default" local interface is out of scope for this specification.
    3. Set the mySocket.localAddress attribute to the local address that the socket is bound to.
  4. If the options argument's localPort member is absent then bind the socket to an ephemeral local port decided by the system and set the mySocket.localPort attribute to this port. Otherwise, bind the socket to the requested local port and set the mySocket.localPort attribute to the local port that the socket is bound to.
  5. Set the mySocket.addressReuse attribute to the value of the options argument's addressReuse member if it is present or to true if the options argument's addressReuse member is not present.
  6. Set the mySocket.noDelay attribute to the value of the options argument's noDelay member if it is present or to true if the options argument's noDelay member is not present.
  7. Set the mySocket.readyState attribute to "opening".
  8. Create a new promise, "openedPromise", and store it so it can later be returned by the opened property.
  9. Create a new promise, "closedPromise", and store it so it can later be returned by the closed property and the close method.
  10. Let the mySocket.readable attribute be a new ReadableStream object, [[!STREAMS]]. The User Agent MUST implement the adaptation layer to [[!STREAMS]] for this new ReadableStream object through implementation of a number of functions that are given as input arguments to the constructor and called by the [[!STREAMS]] implementation. The semantics for these functions are described below:
    • The constructor's start() function is called immediately by the [[!STREAMS]] implementation. The start() function MUST run the following steps:
      1. A TCP connection setup handshake to the requested address and port MUST be performed in the background (without blocking scripts). Return openedPromise.
      2. When the TCP connection has been successfully established the following steps MUST run:
        1. Change the mySocket.readyState attribute's value to "open".
        2. Resolve openedPromise with undefined.
      The following functions are arguments of the constructor's start() function and MUST be called by the start() function implementation according to the following steps:
      • The enqueue() argument of start() is a function that pushes received data into the internal buffer.
        When new TCP data is received the following steps MUST run:
        1. Create a new read-only ArrayBuffer object whose contents are the received TCP data.
        2. Call enqueue() to push the ArrayBuffer into the internal [[!STREAMS]] receive buffer.
        3. If the high watermark of the buffer is reached enqueue() returns false and the TCP flow control MUST be used to stop the data transmission from the remote peer.
      • The close() argument of start() is a function that closes the readable stream.
        Upon detection that the TCP connection has been closed cleanly (initiated either by the server, or by the client application calling close()) through a successful TCP connection closing handshake the following steps MUST run:
        1. Call close().
        2. Set the mySocket.readyState attribute's value to "closed" and release any underlying resources associated with this socket.
        3. Resolve closedPromise with undefined.
      • The error() argument of start() is a function that handles readable stream errors and closes the readble stream.
        Upon detection that the attempt to create a new TCP socket and establish a new TCP connection (mySocket.readyState is "opening") has failed the following steps MUST run:
        1. Call error() with DOMException "NetworkError".
        2. Reject openedPromise with DOMException "NetworkError".
        3. Reject closedPromise with DOMException "NetworkError".
        4. Change the mySocket.readyState attribute's value to "closed" and release any underlying resources associated with this socket.
        Upon detection that the established TCP connection (mySocket.readyState is "open") has been lost the following steps MUST run:
        1. Call error() with DOMException "NetworkError".
        2. Reject closedPromise with DOMException "NetworkError".
        3. Change the mySocket.readyState attribute's value to "closed" and release any underlying resources associated with this socket.
        Upon detection that the TCP connection closing handshake failed (mySocket.readyState is "closing") has failed the following steps MUST run:
        1. Call error() with DOMException "NetworkError".
        2. Reject closedPromise with DOMException "NetworkError".
        3. Change the mySocket.readyState attribute's value to "closed" and release any underlying resources associated with this socket.
        When new TCP data has been received and upon detction that it is not possible to convert the received data to ArrayBuffer, [[!TYPED-ARRAYS]], the following steps MUST run:
        1. Call error() with TypeError.
        2. Reject closedPromise with TypeError.
        3. Change the mySocket.readyState attribute's value to "closed" and release any underlying resources associated with this socket.
    • The constructor's pull() function is called by the [[!STREAMS]] implementation if the internal buffer has been emptied, but the stream's consumer still wants more data. The pull() function MUST run the following steps:
      1. The function MUST resume receiving TCP data through the TCP flow control mechanism.
    • The constructor's cancel() function input argument is called by the [[!STREAMS]] implementation when the ReadbleStream should be canceled. For TCP this means that the TCP connection should be terminated. The cancel() function MUST run the following steps:
      1. If mySocket.readyState is "closing" or "closed" then do nothing and abort the remaning steps.
      2. If mySocket.readyState is "opening" then fail the connection attempt, reject openedPromise and closedPromise with DOMException AbortError and set the mySocket.readyState attribute to "closing".
      3. If mySocket.readyState is "open" then the following steps MUST run:
        1. Call mySocket.writeable.close() to assure that any buffered send data is sent before closing the socket.
        2. Set the mySocket.readyState attribute's value to "closing".
        3. Initiate TCP closing handshake.

      If the constructor's strategy argument is omitted the Default strategy for Readable Streams applies. Currently this means that the ReadableStream object goes to "readable" state after 1 chunk has been enqueued to the internal ReadableStream object's input buffer. An application should call .wait() to be notified when the state changes to "readable". To be further investigated which ReadableStreamStrategy that should be applied to TCP.

  11. Let the mySocket.writeable attribute be a new WritableStream object, [[!STREAMS]]. The User Agent MUST implement the adaptation layer to [[!STREAMS]] for this new WritableStream object through implementation of a number of functions that are given as input arguments to the constructor and called by the [[!STREAMS]] implementation. The semantics for these functions are described below:
    • The constructor's start() function MUST run the following steps:
      1. Create a new promise, "writableStartPromise".
      2. If the attempt to create a new TCP socket and establish a new TCP connection (see the description of the semantics for the mySocket.readable attribute constructor's start() function ) succeded resolve writableStartPromise with undefined, else reject writableStartPromise with DOMException "NetworkError".
    • The constructor's write(chunk) function is called by the [[!STREAMS]] implementation to write data to the remote peer on the TCP connection. The write() function MUST run the following steps:
      1. Create a new promise, "writePromise"
      2. Send TCP data with data passed in the chunk parameter to the address and port of the recipient as stated by the TCPSocket object constructor's remoteAddress and remotePort fields. The data in the chunk parameter can be of any type.
      3. If sending succeed resolve writePromise with undefined, else reject writePromise with DOMException "NetworkError".
    • The constructor's close() function is called by the [[!STREAMS]] implementation to close the writable side of the connection, that is a TCP "half close" is performed. The close() function MUST run the following steps:
      1. If mySocket.readyState is "closing" or "closed" then do nothing.
      2. If mySocket.readyState is "opening" then complete the connection attempt. If succesful send FIN and set the mySocket.readyState attribute to "halfclosed".
      3. If mySocket.readyState is "open" then send FIN and set the mySocket.readyState attribute to "halfclosed".
      Note that the Streams implementation will call close() after all queued-up writes successfully completed.
    • The constructor's abort() function is called by the [[!STREAMS]] implementation to abort the writable side of the connection. This function MUST run the same steps as close() but note that the Streams implementation will throw away any pending queued up chunks.

      If the constructor's strategy argument is omitted the Default strategy for Writable Streams applies. Currently this means that the WriteableStream object goes to "waiting" state after 1 chunk has been written to the internal WriteableStream object's output buffer. This means that the application should call .wait() to be notified of when the state changes to "writable", i.e. the queued chunk has been written to the remote peer and more data chunks could be written. To be further investigated which WritableStreamStrategy that should be applied to TCP.

  12. Return the newly created TCPSocket object ("mySocket") to the application.

The close() method when invoked MUST run the following steps:

  1. Call mysocket.readable.cancel(reason). (Reason codes TBD.)
  2. Return closedPromise.

The halfClose() method when invoked MUST run the following steps:

  1. Call mysocket.writeable.close().

Interface TCPServerSocket

The TCPServerSocket interface supports TCP server sockets that listens to connection attempts from TCP clients

      // 
      // This example shows a simple TCP echo server. 
      // The server will listen on port 6789 and respond back with whatever 
      // has been sent to the server.
      //        
       //  Create a new server socket that listens on port 6789
       var myServerSocket = new TCPServerSocket({"localPort": 6789});

       // Listen for connection attempts from TCP clients.
       listenForConnections();
       function listenForConnections() {
         myServerSocket.listen().then(
             connectedSocket => {
             // A connection has been accepted
             
               console.log ("Connection accepted from address: " + 
                             connectedSocket.remoteAddress + " port: " + 
                             connectedSocket.remotePort);         
               // Wait for data
               waitForData ();
               function waitForData () {  
                 connectedSocket.readable.wait().then(
                   () => {                   
                       // Data in buffer, read it
                       var receivedData = connectedSocket.readable.read();
                       console.log ("Received: " + receivedData);
                       
                       // Send data back
                       connected.writeable.write(receivedData).then(
                         () => {                         
                           console.log ("Sending data succeeded");                      
                         },
                         e => console.error("Failed to send: ", e);     
                       },
                       // Continue to wait for data
                       waitForData ();
                   },                        
                   e => {
                     console.error("Error in connection: ", e);
                     // Continue to wait for data
                     waitForData ();
                   }  
                 );
               
               }
                    
               // Continue to listen for new connections
               listenForConnections();    
             },
             e => {
               console.error("A client connection attempt failed: ", e);

               // Continue to listen for new connections
               listenForConnections();                  
             }  
  
         );
       }

       // Log result of TCP server socket creation attempt. 
       myServerSocket.opened.then(
         () => {
           console.log("TCP server socket created sucessfully");
         },
         e =>console.error("TCP server socket creation failed due to error: ", e);
       );
       
       // Handle TCP server closed, either as a result of the application 
       // calling myServerSocket.close() or due to an error.
       myServerSocket.closed.then(
         () => {
            console.log("TCP server socket has been cleanly closed");
         },
         e => console.error("TCP server socket closed due to error: ", e);
       );

      
readonly attribute DOMString localAddress
The IPv4/6 address of the interface, e.g. wifi or 3G, that the TCPServer Socket object is bound to. Can be set by the options argument in the constructor. If not set the the server will accept connections directed to any IPv4 address and this atribute is set to null.
readonly attribute unsigned short localPort
The local port that the TCPServerSocket object is bound to. Can be set by the options argument in the constructor. If not set the user agent binds the socket to an ephemeral local port decided by the system and sets this atribute to null.
readonly attribute boolean addressReuse
true allows the socket to be bound to a local address/port pair that already is in use. Can be set by the options argument in the constructor. Default is true.
readonly attribute SocketReadyState readyState
The state of the TCP server object. A TCP server socket object can be in "open", "opening" or "closed" states. See enum SocketReadyState for details.
readonly attribute Promise opened
Detects the result of the TCP server socket opening process when the socket is ready to receive connection attempts from clients. Returns the openedPromise that was created in the TCPServerSocket constructor.
readonly attribute Promise closed
Detects when the TCP server socket been closed, either cleanly by the client application calling close()) or through an error situation. Returns the closedPromise that was created in the TCPSocket constructor.
Promise listen()

Listens for incoming connection attempts on the specified port and address. Returns the connectionPromise, which is for a succeful connection resolved with the TCPSocket object for the accepted TCP connection and rejected with DOMException "NetworkError" if there is an error on an incoming connection attempt.

Promise close()

Closes the TCP server socket. If listen() has been called the listening for incoming connections is stopped but existing TCP connections are kept open. Returns the closedPromise that was created in the TCPServerSocket constructor.

When the TCPServerSocket constructor is invoked, the User Agent MUST run the following steps:

  1. Create a new TCPServerSocket object ("myServerSocket").
  2. If the options argument's localAddress member is absent the server will accept connections directed to any IPv4 address and the localAddress attribute is set to null. Otherwise, if the requested local address is a valid IPv4/6 address for a local interface on the device bind the server socket to this local IPv4/6 address and set the localAddress attribute to this address. Else, if the localAddress member is present but it is not a valid local IPv4/6 address for a local interface on the device, throw DOMException InvalidAccessError and abort the remaining steps.
  3. If the options argument's localPort member is absent then bind the socket to an ephemeral local port decided by the system and set the localPort attribute to null. Otherwise, bind the socket to the requested local port and set the localPort attribute to the local port that the socket is bound to.
  4. Set the addressReuse attribute to the value of the options argument's addressReuse member if it is present or to true if the options argument's addressReuse member is not present.
  5. Set the myServerSocket.readyState attribute to "opening".
  6. Create a new promise, "openedPromise", and store it so it can later be returned by the opened property.
  7. Create a new promise, "closedPromise", and store it so it can later be returned by the closed property and the close method.
  8. Return the newly created TCPServerSocket object to the application.

The close method when invoked MUST run the following steps:

  1. If a TCP connection setup is in progress the connection setup is finalized according to the descriptions below.
  2. Stop listening to further connection attempts from clients.
  3. Set the myServerSocket.readyState attribute to "closed".
  4. Resolve closedPromise with undefined.

The listen method when invoked MUST run the following steps:

  1. If myServerSocket.readyState attribute is"closed" then throw DOMException "InvalidStateError" and abort the remaining steps.
  2. Create a new promise, "connectionPromise".
  3. Start listening for connections on the specified local port and address. Return connectionPromise.

When a new TCP server socket has successfully been created the user agent MUST run the following steps:

  1. Change the myServerSocket.readyState attribute's value to "open".
  2. Resolve openedPromise with undefined.

When the attempt to create a new TCP server socket (myServerSocket.readyState is "opening") has failed the user agent MUST run the following steps:

  1. Change the myServerSocket.readyState attribute's value to "closed".
  2. Reject openedPromise with DOMException "NetworkError".
  3. Reject closedPromise with DOMException "NetworkError".

When there is an error on an established TCP server socket (myServerSocket.readyState is "open"), e.g. loss of network contact, the user agent MUST run the following steps:

  1. Change the myServerSocket.readyState attribute's value to "closed".
  2. Reject closedPromise with DOMException "NetworkError".

Upon a new successful connection to the TCP server socket the user agent MUST run the following steps:

  1. Let socket be a new instance of TCPSocket.
  2. Set the remoteAddress attribute of socket to the IPv4/6 address of the peer.
  3. Set the remotePort attribute of socket to the source port of the of the peer.
  4. Set the localAddress attribute of socket to the used local IPv4/6 address.
  5. Set the localPort attribute of socket to the used local source port.
  6. Set the readyState attribute of socket to "open".
  7. Set the bufferedAmount attribute of socket to 0.
  8. Resolve connectionPromise with socket as argument.

Upon a new connection attempt to the TCP server socket that can not be served, e.g. due to max number of open connections, the user agent MUST run the following steps:

  1. Reject connectionPromise with DOMException "NetworkError".

Dictionary UDPMessage

The UDPMessage dictionary represents UDP data including address and port of the remote peer. The field data is mandatory but remoteAddress and remotePort are optional.

ArrayBuffer data
Received UDP data or UDP data to send.
DOMString remoteAddress
The address of the remote machine.
unsigned short remotePort
The port of the remote machine.

Dictionary UDPOptions

States the options for the UDPSocket. An instance of this dictionary can optionally be used in the constructor of the UDPSocket object, where all fields are optional.

DOMString localAddress
The IPv4/6 address of the local interface, e.g. wifi or 3G, that the UDPSocket object is bound to. If the field is omitted, the user agent binds the socket to an IPv4/6 address based on the routing table and possibly a preselect default local interface to use for the selected remoteAddress if this member is present. Else the UDPSocket is unbound to a local interface.
unsigned short localPort
The local port that the UDPSocket object is bound to. If the the field is omitted, the user agent binds the socket to a an ephemeral local port decided by the system.
DOMString remoteAddress
When present the default remote host name or IPv4/6 address that is used for subsequent send() calls.
unsigned short remotePort
When present the default remote port that is used for subsequent send() calls.
boolean addressReuse
true allows the socket to be bound to a local address/port pair that already is in use. Default is true.
boolean loopback
Only applicable for multicast. true means that sent multicast data is looped back to the sender. Default is false.

Dictionary TCPOptions

States the options for the TCPSocket. An instance of this dictionary can optionally be used in the constructor of the TCPSocket object, where all fields are optional.

DOMString localAddress
The IPv4/6 address of the local interface, e.g. wifi or 3G, that the TCPSocket object is bound to. If the field is omitted, the user agent binds the socket to an IPv4/6 address based on the routing table and possibly a preselect default local interface to use for the selected remoteAddress.
unsigned short localPort
The local port that the TCPSocket object is bound to. If the the field is omitted, the user agent binds the socket to an ephemeral local port decided by the system.
boolean addressReuse
true allows the socket to be bound to a local address/port pair that already is in use. Default is true.
boolean noDelay
true if the Nagle algorithm for send coalescing, [[!NAGLE]], is disabled. Default is true.
boolean useSecureTransport
true if socket uses SSL or TLS. Default is false.

Use of secure transport needs more investigation

Dictionary TCPServerOptions

States the options for the TCPServerSocket. An instance of this dictionary can optionally be used in the constructor of the TCPServerSocket object, where all fields are optional.

DOMString localAddress
The IPv4/6 address of the interface, e.g. wifi or 3G, that the TCPServerSocket object is bound to. If the field is omitted, the user agent binds the server socket to the IPv4/6 address of the default local interface.
unsigned short localPort
The local port that the TCPServerSocket object is bound to. If the the field is omitted, the user agent binds the socket to an ephemeral local port decided by the system.
boolean addressReuse
true allows the socket to be bound to a local address/port pair that already is in use. Default is true.
boolean useSecureTransport
true if socket uses SSL or TLS. Default is false.

Use of secure transport needs more investigation

Enums

SocketReadyState

opening
The socket is in opening state, i.e. availability of local address/port is being checked, network status is being checked, etc. For TCP a connection with a remote peer has not yet been established.
open
The socket is ready to use to send and received data. For TCP a connection with a remote peer has been established.
closing
Only used for TCP sockets. The TCP connection is going through the closing handshake, or the close() method has been invoked.
closed
The socket is closed and can not be use to send and received data. For TCP the connection has been closed or could not be opened.
halfclosed
Only used for TCP sockets. The TCP connection has been "halfclosed" by the application, which means that it is not possible to send data but it is still possible to receive.

Acknowledgements

Many thanks to Domenic Denicola, Marcos Caceres, Jonas Sicking, Ke-Fong Lin and Alexandre Morgaut for reviewing the specification and providing very valuable feedback. Also thanks to Sony colleagues Anders Edenbrandt, Anders Isberg and Björn Isaksson for sharing their experience on socket APIs and providing support.