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

This specification is currently undergoing a major rewrite in order to be based on the Streams API. Currently the reference to the Streams API is [[!STREAMS]] but there is ongoing work to align this specification with [[!W3C-STREAMS]].

In the current version only the interfaces TCPSocket and UDPSocket have been rewritten. TCPServerSocket remains to be rewritten.

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 specification we need a better granularity of machine readable errors and therefore the SocketError interface was added. This interface extends DOMError with a machine readble error type providing a better granularity of error reporting. However, the SocketError interface can not be used by promises so I have temporily just stated a DOMException for promises rejection reasons in the specification. This issue must be further explored and aligned with ongoing discussions in W3C, WHAT WG and ECMA. For example see Error objects in W3C APIs.

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]].

The EventHandler interface represents a callback used for event handlers as defined in [[!HTML5]].

The concepts queue a task and fire an event are defined in [[!HTML5]].

The terms event handler and event handler event types are defined in [[!HTML5]].

The task source for all tasks queued in this specification is the WebSocket task source.

Security and privacy considerations

This API must be only exposed to trusted content.

To use this API an application must state a request to get the permission to use the API in the application's manifest. The permission name for this API is raw-socket. See [[!SYSAPPS-RUNTIME]].

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.readableState === "readable") {            
            var msg = mySocket.input.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.input.wait().then(
            receiveMSearchResponses,          
            e => console.error("Receiving error: ", e);
          );     
        }
        
        // Join SSDP multicast group
        mySocket.joinMulticast(address);
        
        // Send SSDP M-SEARCH multicast message
        mySocket.output.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 input
The object that represents the UDP socket's source of data, from which you can read. [[!STREAMS]]
readonly attribute WriteableStream output
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.input 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.output.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.
  12. Let the mySocket.output 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 be omitted as the UDP socket setup is performed in the mySocket.input attribute constructor's start() function.
    • The constructor's write(chunk, done, error) function is called by the [[!STREAMS]] implementation to write UDP data. The write() function MUST run the following steps:
      1. Let the chunk argument be the result of converting data to an UDPMessage (per [[!WEBIDL]] dictionary conversion).
      2. If no default remote address was specified in the UDPSocket's constructor options argument's remoteAddress member and the UDPMesssage object's remoteAddress member is not present or null then throw DOMException InvalidAccessError and abort these steps.
      3. If no default remote port was specified in the UDPSocket's constructor options argument's remotePort member and the UDPMesssage object's remotePort member is not present or null then throw DOMException InvalidAccessError and abort these steps.
      4. 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.
      The following functions are arguments of the constructor's write() function and MUST be called by the write() function implementation:
      • The done() argument of write() is a function that MUST be called when the buffered data has been sent to the remote peer and the underlying resource is ready for more data.
      • The error(errorReason) argument of write() is a function that MUST be called if an error ocurred during writing. (errorReason TBD).
    • The constructor's close() function MUST be omitted as it is not possible to just close the writable side of a UDP socket.
  13. Return the newly created UDPSocket object ("mySocket") to the application.

The close method when invoked MUST run the following steps:

  1. Call mysocket.input.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.output.write("Hello World").then(
           () => {
               
               // Data sent sucessfully, wait for response
               console.log("Data has been sent to server");
               mySocket.input.wait().then(
                   () => {
                   
                       // Data in buffer, read it
                       console.log("Data received from server:" + mySocket.input.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("Socket has been cleanly closed");
         },
         e => console.error("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 input
The object that represents the TCP socket's source of data, from which you can read. [[!STREAMS]]
readonly attribute WriteableStream output
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 UDPSocket 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.input 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 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.output.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.
  11. Let the mySocket.output 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 be omitted as the TCP connection establishment is performed in the mySocket.input attribute constructor's start() function.
    • The constructor's write(chunk, done, error) 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. 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 following functions are arguments of the constuctor's write() function and MUST be called by the write() function implementation:
      • The done() argument of write() is a function that MUST be called when the buffered data has been sent to the remote peer the underlying resource is ready for more data.
      • The error(errorReason) argument of write() is a function that MUST be called if an error ocurred during writing. (errorReason TBD).
    • 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".
  12. Return the newly created TCPSocket object ("mySocket") to the application.

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

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

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

  1. Call mysocket.output.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 what ever 
        // has been sent to the server.
        //        
        try {
            //  Create a new server socket that listens on port 6789
            var myServerSocket = new TCPServerSocket({
                "localPort": 6789
            });

            // The TCP server Socket has been created successfully       
            myServerSocket.onopen = function () {

                myServerSocket.onconnect = function (connectEvent) {
                    var connectedSocket = connectEvent.connectedSocket;
                    // Read the data
                    connectedSocket.ondata = function (messageEvent) {
                        var data = messageEvent.data;
                        try {
                            // Send data back to client
                            var moreBufferingOK = connectedSocket.send(data);
                            console.log('Response sent to client!');
                        } catch (err) {
                            // Sending failed      
                            console.error('Sending failed: ' + err.name);
                        }
                    };

                    // Connection has been closed 
                    connectedSocket.onclose = function {
                        console.log('Connection has been closed');
                    };

                };

            };

            // Handle errors
            myServerSocket.onerror = function (err) {
                console.error('Error: ' + err.name);
            };
        } catch (err) {
            // Handle runtime exception    
            console.error('Could not create a TCP server socket: ' + err.name);
        }
      
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.
attribute EventHandler onopen
Event handler that corresponds to the open event, which is fired when the socket is open and ready to receive connection attempts from clients. If the creation of the server socket fails the error event will be fired instead.
attribute EventHandler onconnect
Event handler that corresponds to the connect event, which is fired repeatedly and asynchronously after the TCPServerSocket object has been created, every time an incoming connection attempt on the specified port and address has been accepted.
attribute EventHandler onerror
Event handler that corresponds to the error event, which is fired when there is an error on the server socket. The data attribute of the event passed to the onerror handler will have a description of the kind of error.
attribute EventHandler onconnecterror
Event handler that corresponds to the connecterror event, which is fired repeatedly and asynchronously after the TCPServerSocket object has been created, every time there is an error on an incoming connection attempt. The data attribute of the event passed to the onconnecterror handler will have a description of the kind of error.
void close()

Closes the TCP server socket, i.e. listening for incoming connections is stopped. Existing TCP connections are kept open.

void suspend()

Pause listening for incoming connections and invocations of the onconnecion handler until resume() is called.

void resume()

Resume listening for incoming connections and invocations of the onconnecion handler as usual.

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

  1. 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, bind the socket to the IPv4/6 address of the requested local interface and set the localAddress attribute to the local address that the socket is bound to.
  2. 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.
  3. 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.
  4. Set the mySocket.readyState attribute to "opening".
  5. 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 mySocket.readyState attribute to "closed".

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

  1. Create a new instance of ConnectEvent.
  2. Let socket be a new instance of TCPSocket.
  3. Set the remoteAddress attribute of socket to the IPv4/6 address of the peer.
  4. Set the remotePort attribute of socket to the source port of the of the peer.
  5. Set the localAddress attribute of socket to the used local IPv4/6 address.
  6. Set the localPort attribute of socket to the used local source port.
  7. Set the mySocket.readyState attribute of socket to "open".
  8. Set the bufferedAmount attribute of socket to 0.
  9. Set the connectedSocket attribute of the ConnectEvent object to socket.
  10. queue a task to fire an event named connect with the newly created ConnectEvent instance at the TCPServerSocket object.

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

  1. Change the mySocket.readyState attribute's value to "open".
  2. Start listening for connections on the specified local port and address.
  3. queue a task to fire an event named open at the TCPServerSocket object.

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

  1. Change the mySocket.readyState attribute's value to "closed".
  2. Create a new instance of SocketErrorEvent.
  3. Set the error.name attribute of the SocketErrorEvent object to "NetworkError".
  4. Set the error.type attribute of the SocketErrorEvent object to the reason for the failed socket creation attempt. See enum SocketErrorType.
  5. Set the error.message attribute of the SocketErrorEvent object to an informative message stating the reason for the error.
  6. queue a task to fire an event named error with the newly created SocketErrorEvent instance at the TCPServerSocket object.

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. Create a new instance of SocketErrorEvent.
  2. Set the error.name attribute of the SocketErrorEvent object to "NetworkError".
  3. Set the error.type attribute of the SocketErrorEvent object to the reason for the failed socket creation attempt. See enum SocketErrorType.
  4. Set the error.message attribute of the SocketErrorEvent object to an informative message stating the reason for the error.
  5. queue a task to fire an event named connecterror with the newly created SocketErrorEvent instance at the TCPServerSocket object.

Event handlers

Below is a list of event handler and corresponding event handler event types that MUST be supported as attributes by the TCPServerSocket object.

event handler event handler event type
onopen open
onconnect connect
onerror error
onconnecterror connecterror

The connect event MUST implement the ConnectEvent interface.

The error event and the connecterror event MUST implement the SocketErrorEvent interface.

Interface ConnectEvent

The ConnectEvent interface represents events related to accepted connections to a TCP server socket.

readonly attribute TCPSocket connectedSocket
The new TCP socket object for the accepted socket. This new socket object is to be used for further communication with the client.

Interface SocketErrorEvent

The SocketErrorEvent interface represents events stating errors.

readonly attribute SocketError error
The detected error.

Interface SocketError

The SocketError interface represents errors in the Raw Socket API.

readonly attribute SocketErrorType type
Error type specific for the socket API that details the error in addition to the error names defined for DOMError, [[!DOM]].

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.

SocketErrorType

no_network_contact
There is no contact with the network.
udp_error
There is an error in the underlying udp protocol layer.
tcp_error
There is an error in the underlying tcp protocol layer.
tcp_peer_does_not_respond
Peer does not respond to the TCP connection attempt.
tcp_connection_not_accepted
Peer does not accept the TCP connection attempt.
tcp_connection_lost
The TCP connection was lost.
received_data_error
The received data can not be convertet to ArrayBuffer.
local_address_port_already_in_use
It is not possible to bind the socket to the requested local address/port pair as it is already in use.
send_buffer_full
The send buffer is full. Application should wait for a drain event
tcp_server_max_connections
The TCP server can not accept more connections as the number of max open connections is reached.
tcp_server_connection_not_accepted
The TCP server does not accept the connection attempt.

Acknowledgements

Many thanks to 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.