This specification defines an API that allows web applications to talk to servers and devices that have their own protocols incompatible with those available on the web.

This is a work in progress. All contributions welcome.

{{TCPSocket}} interface

      [Exposed=(Window,Worker), SecureContext]
      interface TCPSocket {
        constructor(DOMString remoteAddress,
                    unsigned short remotePort,
                    optional TCPSocketOptions options = {});

        readonly attribute Promise<TCPSocketOpenInfo> opened;
        readonly attribute Promise<undefined> closed;

        Promise<undefined> close();
      };
    

Methods on this interface typically complete asynchronously, queuing work on the TCPSocket task source.

Instances of {{TCPSocket}} are created with the internal slots described in the following table:

Internal slot Initial value Description (non-normative)
[[\readable]] `null` A {{ReadableStream}} that receives data from the socket
[[\writable]] `null` A {{WritableStream}} that transmits data to the socket
[[\openedPromise]] `new Promise` A {{Promise}} used to wait for the socket to be opened. Corresponds to the {{TCPSocket/opened}} member.
[[\closedPromise]] `new Promise` A {{Promise}} used to wait for the socket to close or error. Corresponds to the {{TCPSocket/closed}} member.

constructor() method

The {{TCPSocket/constructor()}} steps are:
  1. If [=this=]'s [=relevant global object=]'s [=associated Document=] is not [=allowed to use=] the [=policy-controlled feature=] named "[=policy-controlled feature/direct-sockets=]", throw a "{{NotAllowedError}}" {{DOMException}}.
  2. If |options|["{{TCPSocketOptions/keepAliveDelay}}"] is less than 1,000, throw a {{TypeError}}.
  3. If |options|["{{TCPSocketOptions/sendBufferSize}}"] is equal to 0, throw a {{TypeError}}.
  4. If |options|["{{TCPSocketOptions/receiveBufferSize}}"] is equal to 0, throw a {{TypeError}}.
  5. Perform the following steps [=in parallel=].
    1. Invoke the operating system to open the TCP socket using the given |remoteAddress| and |remotePort| and the connection parameters (or their defaults) specified in |options|.
    2. If this fails for any reason, [=queue a global task=] on the [=relevant global object=] of [=this=] using the [=TCPSocket task source=] to run the following steps:
      1. [=Reject=] the {{TCPSocket/[[openedPromise]]}} with a "{{NetworkError}}" {{DOMException}}.
      2. [=Reject=] the {{TCPSocket/[[closedPromise]]}} with a "{{NetworkError}}" {{DOMException}}.
    3. On success, [=queue a global task=] on the [=relevant global object=] of [=this=] using the [=TCPSocket task source=] to run the following steps:
      1. [=initialize TCPSocket readable stream|Initialize=] {{TCPSocket/[[readable]]}}.
      2. [=initialize TCPSocket writable stream|Initialize=] {{TCPSocket/[[writable]]}}.
      3. Let |openInfo:TCPSocketOpenInfo| be a new {{TCPSocketOpenInfo}}.
      4. Set |openInfo|["{{TCPSocketOpenInfo/readable}}"] to [=this=].{{TCPSocket/[[readable]]}}.
      5. Set |openInfo|["{{TCPSocketOpenInfo/writable}}"] to [=this=].{{TCPSocket/[[writable]]}}.
      6. Populate the remaining fields of |openInfo| using the information provided by the operating system: |openInfo|["{{TCPSocketOpenInfo/remoteAddress}}"], |openInfo|["{{TCPSocketOpenInfo/remotePort}}"], |openInfo|["{{TCPSocketOpenInfo/localAddress}}"] and |openInfo|["{{TCPSocketOpenInfo/localPort}}"].
      7. [=Resolve=] [=this=].{{TCPSocket/[[openedPromise]]}} with |openInfo|.

TCPSocketOptions dictionary

          dictionary TCPSocketOptions {
            [EnforceRange] unsigned long sendBufferSize;
            [EnforceRange] unsigned long receiveBufferSize;

            boolean noDelay = false;
            [EnforceRange] unsigned long keepAliveDelay;
          };
        
sendBufferSize member
The requested send buffer size, in bytes. If not specified, then platform-specific default value will be used.
receiveBufferSize member
The requested receive buffer size, in bytes. If not specified, then platform-specific default value will be used.
noDelay member
Enables the `TCP_NODELAY` option, disabling Nagle's algorithm.
No-Delay is disabled by default.
keepAliveDelay member
If specified, enables TCP Keep-Alive by setting `SO_KEEPALIVE` option on the socket to `true`. The way the actual delay is set is platform-specific:
  1. On Linux & ChromeOS `keepAliveDelay` is applied to `TCP_KEEPIDLE` and `TCP_KEEPINTVL`;
  2. On MacOS `keepAliveDelay` affects `TCP_KEEPALIVE`;
  3. On Windows `keepAliveDelay` is replicated to `keepalivetime` and `keepaliveinterval` of `SIO_KEEPALIVE_VALS`.
Keep-Alive is disabled by default.

{{TCPSocket/[[readable]]}} attribute (internal)

The steps to initialize the TCPSocket readable stream are:
  1. Let |stream:ReadableStream| be a [=new=] {{ReadableStream}}.
  2. Let |pullAlgorithm| be the following steps:
    1. Let |desiredSize| be the desired size of [=this=].{{TCPSocket/[[readable]]}}'s internal queue.
    2. Run the following steps in parallel:
      1. Invoke the operating system to read up to |desiredSize| bytes from the socket, placing the result in the [=byte sequence=] |bytes|.
      2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=TCPSocket task source=] to run the following steps:
        1. If the connection was closed gracefully, run the following steps:
          1. Invoke [=ReadableStream/close=] on [=this=].{{TCPSocket/[[readable]]}}.
          2. Invoke the steps to [=handle closing the TCPSocket readable stream=].
          This is triggered by the peer sending a packet with the FIN flag set and is typically indicated by the operating system returning 0 bytes when asked for more data from the socket.
        2. If no errors were encountered run the following steps:
          1. Let |buffer| be a [=new=] {{ArrayBuffer}} created from |bytes|.
          2. Let |chunk| be a [=new=] {{Uint8Array}} view over |buffer|, who's length is the length of |bytes|.
          3. Invoke [=ReadableStream/enqueue=] on [=this=].{{TCPSocket/[[readable]]}} with |chunk|.
        3. If a network or operating system error was encountered, invoke [=ReadableStream/error=] on [=this=].{{TCPSocket/[[readable]]}} with a "{{NetworkError}}" {{DOMException}} and invoke the steps to [=handle closing the TCPSocket readable stream=].
    3. Return [=a promise resolved with=] `undefined`.
  3. Let |cancelAlgorithm| be the following steps:
    1. Invoke the steps to [=handle closing the TCPSocket readable stream=].
    2. Return [=a promise resolved with=] `undefined`.
  4. [=ReadableStream/Set up=] |stream| with pullAlgorithm set to |pullAlgorithm|, cancelAlgorithm set to |cancelAlgorithm|, highWaterMark set to an implementation-defined value.
  5. Set [=this=].{{TCPSocket/[[readable]]}} to |stream|.
To handle closing the TCPSocket readable stream perform the following steps:
  1. If [=this=].{{TCPSocket/[[writable]]}} is active, abort these steps.
  2. Run the following steps [=in parallel=].
    1. Invoke the operating system to close the socket.
    2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=TCPSocket task source=] to run the following steps:
      • If [=this=].{{TCPSocket/[[writable]]}} is errored, [=reject=] [=this=].{{TCPSocket/[[closedPromise]]}} with [=this=].{{TCPSocket/[[writable]]}}.`[[storedPromise]]`.
      • Otherwise, if [=this=].{{TCPSocket/[[readable]]}} is errored, [=reject=] [=this=].{{TCPSocket/[[closedPromise]]}} with [=this=].{{TCPSocket/[[readable]]}}.`[[storedPromise]]`.
      • Otherwise, [=resolve=] [=this=].{{TCPSocket/[[closedPromise]]}} with `undefined`.

{{TCPSocket/[[writable]]}} attribute (internal)

The steps to initialize the TCPSocket writable stream are:
  1. Let |stream:WritableStream| be a [=new=] {{WritableStream}}.
  2. Let |signal:AbortSignal| be |stream|'s [=WritableStream/signal=].
  3. Let |writeAlgorithm| be the following steps, given |chunk|:
    1. Let |promise:Promise| be [=a new promise=].
    2. Assert: |signal| is not [=AbortSignal/aborted=].
    3. If |chunk| cannot be [=converted to an IDL value=] of type {{BufferSource}}, reject |promise| with a {{TypeError}} and return |promise|. Otherwise, save the result of the conversion in |source:BufferSource|.
    4. [=Get a copy of the buffer source=] |source| and save the result in |bytes|.
    5. [=In parallel=], run the following steps:
      1. Invoke the operating system to write |bytes| to the socket.
        The operating system may return from this operation once |bytes| has been queued for transmission rather than after it has been transmitted.
      2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=TCPSocket task source=] to run the following steps:
        1. If the chunk was successfully written, [=resolve=] |promise| with `undefined`.
          [[STREAMS]] specifies that |writeAlgorithm| will only be invoked after the {{Promise}} returned by a previous invocation of this algorithm has resolved. For efficiency an implementation is allowed to resolve this {{Promise}} early in order to coalesce multiple chunks waiting in the {{WritableStream}}'s internal queue into a single request to the operating system.
        2. If a network or operating system error was encountered:
          1. [=Reject=] |promise| with a "{{NetworkError}}" {{DOMException}}.
          2. Invoke the steps to [=handle closing the TCPSocket writable stream=].
        3. If |signal| is [=AbortSignal/aborted=], [=reject=] |promise| with |signal|'s [=AbortSignal/abort reason=].
    6. Return |promise|.
  4. Let |abortAlgorithm| be the following steps:
    1. Let |promise| be [=a new promise=].
    2. Run the following steps [=in parallel=]:
      1. Invoke the operating system to shutdown the socket for writing.
      2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=TCPSocket task source=] to run the following steps:
        1. Invoke the steps to [=handle closing the TCPSocket writable stream=].
        2. [=Resolve=] |promise| with `undefined`.
    3. Return |promise|.
  5. Let |closeAlgorithm| be the following steps:
    1. Let |promise| be [=a new promise=].
    2. Run the following steps [=in parallel=].
      1. Invoke the operating system to shutdown the socket for writing.
      2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=TCPSocket task source=] to run the following steps:
        1. Invoke the steps to [=handle closing the TCPSocket writable stream=].
        2. If |signal| is [=AbortSignal/aborted=], [=reject=] |promise| with |signal|'s [=AbortSignal/abort reason=].
        3. [=Resolve=] |promise| with `undefined`.
    3. Return |promise|.
  6. [=WritableStream/Set up=] |stream| with writeAlgorithm set to |writeAlgorithm|, abortAlgorithm set to |abortAlgorithm|, closeAlgorithm set to |closeAlgorithm|, highWaterMark set to an implementation-defined value.
  7. [=AbortSignal/Add=] the following abort steps to |signal|:
    1. Cause any invocation of the operating system to write to the socket to return as soon as possible no matter how much data has been written.
  8. Set [=this=].{{TCPSocket/[[writable]]}} to |stream|.
To handle closing the TCPSocket writable stream perform the following steps:
  1. If [=this=].{{TCPSocket/[[readable]]}} is active, abort these steps.
  2. Run the following steps [=in parallel=].
    1. Invoke the operating system to close the socket.
    2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=TCPSocket task source=] to run the following steps:
      • If [=this=].{{TCPSocket/[[readable]]}} is errored, [=reject=] [=this=].{{TCPSocket/[[closedPromise]]}} with [=this=].{{TCPSocket/[[readable]]}}.`[[storedPromise]]`.
      • Otherwise, if [=this=].{{TCPSocket/[[writable]]}} is errored, [=reject=] [=this=].{{TCPSocket/[[closedPromise]]}} with [=this=].{{TCPSocket/[[writable]]}}.`[[storedPromise]]`.
      • Otherwise, [=resolve=] [=this=].{{TCPSocket/[[closedPromise]]}} with `undefined`.

opened attribute

When called, returns the [=this=].{{TCPSocket/[[openedPromise]]}}.

TCPSocketOpenInfo dictionary

          dictionary TCPSocketOpenInfo {
            ReadableStream readable;
            WritableStream writable;

            DOMString remoteAddress;
            unsigned short remotePort;

            DOMString localAddress;
            unsigned short localPort;
          };
        
readable member
The readable side of the socket. Set to {{TCPSocket/[[readable]]}}.
writable member
The writable side of the socket. Set to {{TCPSocket/[[writable]]}}.
remoteAddress member
Resolved remote IP address that the socket is connected to.
remotePort member
Remote port that the socket is connected to.
localAddress member
Local IP address that the socket is bound to.
localPort member
Local port that the socket is bound to.

closed attribute

When called, returns the [=this=].{{TCPSocket/[[closedPromise]]}}.

close() method

The {{TCPSocket/close()}} method steps are:
  1. If [=this=].{{TCPSocket/[[openedPromise]]}} is rejected or not yet resolved, [=reject=] with "{{InvalidStateError}}" {{DOMException}}.
  2. If [=this=].{{TCPSocket/[[closedPromise]]}} is settled, return [=this=].{{TCPSocket/[[closedPromise]]}}.
  3. If [=this=].{{TCPSocket/[[readable]]}} or [=this=].{{TCPSocket/[[writable]]}} are locked, [=reject=] with "{{InvalidStateError}}" {{DOMException}}.
  4. Let |cancelPromise:Promise| be the result of invoking [=ReadableStream/cancel=] on [=this=].{{TCPSocket/[[readable]]}}.
  5. Set |cancelPromise|.[[\PromiseIsHandled]] to true.
  6. Let |abortPromise:Promise| be the result of invoking [=WritableStream/abort=] on [=this=].{{TCPSocket/[[writable]]}}.
  7. Set |abortPromise|.[[\PromiseIsHandled]] to true.
  8. Return [=this=].{{TCPSocket/[[closedPromise]]}}.

{{UDPSocket}} interface

      [Exposed=(Window,Worker), SecureContext]
      interface UDPSocket {
        constructor(UDPSocketOptions options);

        readonly attribute Promise<UDPSocketOpenInfo> opened;
        readonly attribute Promise<undefined> closed;

        Promise<undefined> close();
      };
    
Methods on this interface typically complete asynchronously, queuing work on the UDPSocket task source.

Instances of {{UDPSocket}} are created with the internal slots described in the following table:

Internal slot Initial value Description (non-normative)
[[\readable]] `null` A {{ReadableStream}} that receives data from the socket
[[\writable]] `null` A {{WritableStream}} that transmits data to the socket
[[\openedPromise]] `new Promise` A {{Promise}} used to wait for the socket to be opened. Corresponds to the {{UDPSocket/opened}} member.
[[\closedPromise]] `new Promise` A {{Promise}} used to wait for the socket to close or error. Corresponds to the {{UDPSocket/closed}} member.

constructor() method

The {{UDPSocket/constructor()}} steps are:
  1. If [=this=]'s [=relevant global object=]'s [=associated Document=] is not [=allowed to use=] the [=policy-controlled feature=] named "[=policy-controlled feature/direct-sockets=]", throw a "{{NotAllowedError}}" {{DOMException}}.
  2. If |options|["{{UDPSocketOptions/sendBufferSize}}"] is equal to 0, throw a {{TypeError}}.
  3. If |options|["{{UDPSocketOptions/receiveBufferSize}}"] is equal to 0, throw a {{TypeError}}.
  4. Perform the following steps [=in parallel=].
    1. Invoke the operating system to open the UDP socket using the given |remoteAddress| and |remotePort| and the parameters (or their defaults) specified in |options|.
    2. If this fails for any reason, [=queue a global task=] on the [=relevant global object=] of [=this=] using the [=UDPSocket task source=] to run the following steps:
      1. [=Reject=] the {{UDPSocket/[[openedPromise]]}} with a "{{NetworkError}}" {{DOMException}}.
      2. [=Reject=] the {{UDPSocket/[[closedPromise]]}} with a "{{NetworkError}}" {{DOMException}}.
    3. On success, [=queue a global task=] on the [=relevant global object=] of [=this=] using the [=UDPSocket task source=] to run the following steps:
      1. [=initialize UDPSocket readable stream|Initialize=] {{UDPSocket/[[readable]]}}.
      2. [=initialize UDPSocket writable stream|Initialize=] {{UDPSocket/[[writable]]}}.
      3. Let |openInfo:UDPSocketOpenInfo| be a new {{UDPSocketOpenInfo}}.
      4. Set |openInfo|["{{UDPSocketOpenInfo/readable}}"] to [=this=].{{UDPSocket/[[readable]]}}.
      5. Set |openInfo|["{{UDPSocketOpenInfo/writable}}"] to [=this=].{{UDPSocket/[[writable]]}}.
      6. Populate the remaining fields of |openInfo| using the information provided by the operating system: |openInfo|["{{UDPSocketOpenInfo/remoteAddress}}"], |openInfo|["{{UDPSocketOpenInfo/remotePort}}"], |openInfo|["{{UDPSocketOpenInfo/localAddress}}"] and |openInfo|["{{UDPSocketOpenInfo/localPort}}"].
      7. Resolve [=this=].{{UDPSocket/[[openedPromise]]}} with |openInfo|.

UDPSocketOptions dictionary

          dictionary UDPSocketOptions {
            required DOMString remoteAddress;
            [EnforceRange] required unsigned short remotePort;

            [EnforceRange] unsigned long sendBufferSize;
            [EnforceRange] unsigned long receiveBufferSize;
          };
        
remoteAddress member
The remote IP address to connect the socket to.
remotePort member
The remote port to connect the socket to.
sendBufferSize member
The requested send buffer size, in bytes. If not specified, then platform-specific default value will be used.
receiveBufferSize member
The requested receive buffer size, in bytes. If not specified, then platform-specific default value will be used.

{{UDPSocket/[[readable]]}} attribute (internal)

The steps to initialize the UDPSocket readable stream are:
  1. Let |stream:ReadableStream| be a [=new=] {{ReadableStream}}.
  2. Let |pullAlgorithm| be the following steps:
    1. Let |desiredSize| be the desired size of [=this=].{{UDPSocket/[[readable]]}}'s internal queue.
    2. Run the following steps in parallel:
      1. Invoke the operating system to provide up to |desiredSize| UDP packets from the socket.
      2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=UDPSocket task source=] to run the following steps for each received packet:
        1. If no errors were encountered, for each packet received run the following steps:
          1. Let |bytes| be a [=byte sequence=] containing the packet payload.
          2. Let |buffer| be a [=new=] {{ArrayBuffer}} created from |bytes|.
          3. Let |chunk| be a [=new=] {{Uint8Array}} view over |buffer|, who's length is the length of |bytes|.
          4. Let |message:UDPMessage| be a new {{UDPMessage}}.
          5. Set |message|["{{UDPMessage/data}}"] to |chunk|.
          6. Set |message|["{{UDPMessage/remoteAddress}}"] to the source address of the packet.
          7. Set |message|["{{UDPMessage/remotePort}}"] to the source port of the packet.
          8. Invoke [=ReadableStream/enqueue=] on [=this=].{{UDPSocket/[[readable]]}} with |message|.
        2. If a network or operating system error was encountered, invoke [=ReadableStream/error=] on [=this=].{{UDPSocket/[[readable]]}} with a "{{NetworkError}}" {{DOMException}}, discard other packets and invoke the steps to [=handle closing the UDPSocket readable stream=].
    3. Return [=a promise resolved with=] `undefined`.
  3. Let |cancelAlgorithm| be the following steps:
    1. Invoke the steps to [=handle closing the UDPSocket readable stream=].
    2. Return [=a promise resolved with=] `undefined`.
  4. [=ReadableStream/Set up=] |stream| with pullAlgorithm set to |pullAlgorithm|, cancelAlgorithm set to |cancelAlgorithm|, highWaterMark set to an implementation-defined value.
  5. Set [=this=].{{UDPSocket/[[readable]]}} to |stream|.
To handle closing the UDPSocket readable stream perform the following steps:
  1. If [=this=].{{UDPSocket/[[writable]]}} is active, abort these steps.
  2. Run the following steps [=in parallel=].
    1. Invoke the operating system to close the socket.
    2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=UDPSocket task source=] to run the following steps:
      • If [=this=].{{UDPSocket/[[writable]]}} is errored, [=reject=] [=this=].{{UDPSocket/[[closedPromise]]}} with [=this=].{{UDPSocket/[[writable]]}}.`[[storedPromise]]`.
      • Otherwise, if [=this=].{{UDPSocket/[[readable]]}} is errored, [=reject=] [=this=].{{UDPSocket/[[closedPromise]]}} with [=this=].{{UDPSocket/[[readable]]}}.`[[storedPromise]]`.
      • Otherwise, [=resolve=] [=this=].{{UDPSocket/[[closedPromise]]}} with `undefined`.

UDPMessage dictionary

          dictionary UDPMessage {
            BufferSource data;
            DOMString remoteAddress;
            unsigned short remotePort;
          };
        
data member
The user message represented as {{BufferSource}}.
Note that for {{UDPSocket/[[readable]]}} the underlying type is always {{Uint8Array}}.
remoteAddress member
The remote address where the message came from.
remotePort member
The remote port where the message came from.
This spec currently only covers the case of "connected" UDP sockets which are supposed to exchange packets with one address specified in the constructor. For this reason {{UDPSocket/[[writable]]}} doesn't support sending packets to arbitrary {{UDPMessage/remoteAddress}}/{{UDPMessage/remotePort}}.

{{UDPSocket/[[writable]]}} attribute (internal)

The steps to initialize the UDPSocket writable stream are:
  1. Let |stream:WritableStream| be a [=new=] {{WritableStream}}.
  2. Let |signal:AbortSignal| be |stream|'s [=WritableStream/signal=].
  3. Let |writeAlgorithm| be the following steps, given |chunk|:
    1. Let |promise:Promise| be [=a new promise=].
    2. Assert: |signal| is not [=AbortSignal/aborted=].
    3. Let |message:UDPMessage| be a new {{UDPMessage}}.
    4. If |chunk| cannot be [=converted to an IDL value=] of type {{UDPMessage}}, reject |promise| with a {{TypeError}} and return |promise|. Otherwise, save the result of the conversion in |message|.
    5. If either |message|["{{UDPMessage/remoteAddress}}"] or |message|["{{UDPMessage/remotePort}}"] is specified, reject |promise| with a {{TypeError}} and return |promise|.
      The |message|["{{UDPMessage/remoteAddress}}"] and |message|["{{UDPMessage/remotePort}}"] currently have no effect on sending packets since the UDP socket is only allowed to operate in the connected mode.
    6. [=Get a copy of the buffer source=] |message|["{{UDPMessage/data}}"] and save the result in |bytes|.
    7. [=In parallel=], run the following steps:
      1. Invoke the operating system to send |bytes| to the socket.
        The operating system may return from this operation once |bytes| has been queued for transmission rather than after it has been transmitted.
      2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=UDPSocket task source=] to run the following steps:
        1. If the data was successfully written, [=resolve=] |promise| with `undefined`.
        2. If a network or operating system error was encountered:
          1. [=Reject=] |promise| with a "{{NetworkError}}" {{DOMException}}.
          2. Invoke the steps to [=handle closing the UDPSocket writable stream=].
        3. If |signal| is [=AbortSignal/aborted=], [=reject=] |promise| with |signal|'s [=AbortSignal/abort reason=].
    8. Return |promise|.
  4. Let |abortAlgorithm| be the following steps:
    1. Invoke the steps to [=handle closing the UDPSocket writable stream=].
    2. Return [=a promise resolved with=] `undefined`.
  5. Let |closeAlgorithm| be the following steps:
    1. Invoke the steps to [=handle closing the UDPSocket writable stream=].
    2. Return [=a promise resolved with=] `undefined`.
  6. [=WritableStream/Set up=] |stream| with writeAlgorithm set to |writeAlgorithm|, abortAlgorithm set to |abortAlgorithm|, closeAlgorithm set to |closeAlgorithm|, highWaterMark set to an implementation-defined value.
  7. [=AbortSignal/Add=] the following abort steps to |signal|:
    1. Cause any invocation of the operating system to write to the socket to return as soon as possible no matter how much data has been written.
  8. Set [=this=].{{UDPSocket/[[writable]]}} to |stream|.
To handle closing the UDPSocket writable stream perform the following steps:
  1. If [=this=].{{UDPSocket/[[readable]]}} is active, abort these steps.
  2. Run the following steps [=in parallel=].
    1. Invoke the operating system to close the socket.
    2. [=Queue a global task=] on the [=relevant global object=] of [=this=] using the [=UDPSocket task source=] to run the following steps:
      • If [=this=].{{UDPSocket/[[readable]]}} is errored, [=reject=] [=this=].{{UDPSocket/[[closedPromise]]}} with [=this=].{{UDPSocket/[[readable]]}}.`[[storedPromise]]`.
      • Otherwise, if [=this=].{{UDPSocket/[[writable]]}} is errored, [=reject=] [=this=].{{UDPSocket/[[closedPromise]]}} with [=this=].{{UDPSocket/[[writable]]}}.`[[storedPromise]]`.
      • Otherwise, [=resolve=] [=this=].{{UDPSocket/[[closedPromise]]}} with `undefined`.

opened attribute

When called, returns the [=this=].{{UDPSocket/[[openedPromise]]}}.

UDPSocketOpenInfo dictionary

          dictionary UDPSocketOpenInfo {
            ReadableStream readable;
            WritableStream writable;

            DOMString remoteAddress;
            unsigned short remotePort;

            DOMString localAddress;
            unsigned short localPort;
          };
        
readable member
The readable side of the socket. Set to {{UDPSocket/[[readable]]}}.
writable member
The writable side of the socket. Set to {{UDPSocket/[[writable]]}}.
remoteAddress member
Resolved remote IP address that the socket is communicating with.
remotePort member
Remote port that the socket is communicating with.
localAddress member
Local IP address that the socket is bound to.
localPort member
Local port that the socket is bound to.

closed attribute

When called, returns the [=this=].{{UDPSocket/[[closedPromise]]}}.

close() method

The {{UDPSocket/close()}} method steps are:
  1. If [=this=].{{UDPSocket/[[openedPromise]]}} is rejected or not yet resolved, [=reject=] with "{{InvalidStateError}}" {{DOMException}}.
  2. If [=this=].{{UDPSocket/[[closedPromise]]}} is settled, return [=this=].{{UDPSocket/[[closedPromise]]}}.
  3. If [=this=].{{UDPSocket/[[readable]]}} or [=this=].{{UDPSocket/[[writable]]}} are locked, [=reject=] with "{{InvalidStateError}}" {{DOMException}}.
  4. Let |cancelPromise:Promise| be the result of invoking [=ReadableStream/cancel=] on [=this=].{{UDPSocket/[[readable]]}}.
  5. Set |cancelPromise|.[[\PromiseIsHandled]] as handled.
  6. Let |abortPromise:Promise| be the result of invoking [=WritableStream/abort=] on [=this=].{{UDPSocket/[[writable]]}}.
  7. Set |abortPromise|.[[\PromiseIsHandled]] as handled.
  8. Return [=this=].{{UDPSocket/[[closedPromise]]}}.

Integrations

Permissions Policy

This specification defines a feature that controls whether {{TCPSocket}} and {{UDPSocket}} classes may be created.

The feature name for this feature is "direct-sockets"`.

The default allowlist for this feature is `'self'`.

A document’s permission policy determines whether a `new TCPSocket(...)` or `new UDPSocket(...)` call rejects with a {{"NotAllowedError"}} {{DOMException}}.

Security and privacy considerations