net.i2p.client

## Interface I2PSession

- All Known Implementing Classes:
    I2PSessionImpl, I2PSessionImpl2, I2PSessionMuxedImpl, I2PSimpleSession, SubSession

      public interface I2PSession

  Define the standard means of sending and receiving messages on the I2P network by using the I2CP (the client protocol). This is done over a bidirectional TCP socket. End to end encryption in I2PSession was disabled in release 0.6. Periodically the router will ask the client to authorize a new set of tunnels to be allocated to the client, which the client can accept by sending a `LeaseSet` signed by the `Destination`. In addition, the router may on occasion provide the client with an updated clock offset so that the client can stay in sync with the network (even if the host computer's clock is off).

- - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `static int` | `PORT_ANY`
    `static int` | `PORT_UNSPECIFIED`
    `static int` | `PROTO_ANY`
    `static int` | `PROTO_DATAGRAM` A repliable and signed datagram
    `static int` | `PROTO_DATAGRAM_RAW` A raw (unsigned, unrepliable) datagram
    `static int` | `PROTO_DATAGRAM2` A repliable and signed datagram.
    `static int` | `PROTO_DATAGRAM3` A repliable but unsigned datagram.
    `static int` | `PROTO_STREAMING`
    `static int` | `PROTO_UNSPECIFIED`

  - ### Method Summary

    All Methods Instance Methods Abstract Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `addMuxedSessionListener(I2PSessionMuxedListener l, int proto, int port)` Listen on specified protocol and port, and receive notification of proto, fromPort, and toPort for every message.
    `void` | `addSessionListener(I2PSessionListener lsnr, int proto, int port)` Listen on specified protocol and port.
    `I2PSession` | `addSubsession(InputStream privateKeyStream, Properties opts)`
    `int[]` | `bandwidthLimits()` Get the current bandwidth limits.
    `void` | `connect()` Actually connect the session and start receiving/sending messages.
    `void` | `destroySession()` Tear down the session and release any resources.
    `Destination` | `getMyDestination()` Retrieve the Destination this session serves as the endpoint for.
    `long` | `getOfflineExpiration()` Get the offline expiration
    `Signature` | `getOfflineSignature()`
    `SigningPrivateKey` | `getPrivateKey()` Retrieve the signing SigningPrivateKey associated with the Destination.
    `String` | `getRouterVersion()` Always valid in RouterContext.
    `List<I2PSession>` | `getSubsessions()`
    `SigningPublicKey` | `getTransientSigningPublicKey()`
    `boolean` | `isClosed()` Have we closed the session?
    `boolean` | `isOffline()` Does this session have offline and transient keys?
    `Destination` | `lookupDest(Hash h)` Lookup a Destination by Hash.
    `Destination` | `lookupDest(Hash h, long maxWait)` Lookup a Destination by Hash.
    `LookupResult` | `lookupDest(Hash h, long maxWait, LookupCallback callback)` Lookup a Destination by hostname.
    `Destination` | `lookupDest(String name)` Ask the router to lookup a Destination by host name.
    `Destination` | `lookupDest(String name, long maxWait)` Ask the router to lookup a Destination by host name.
    `LookupResult` | `lookupDest(String name, long maxWait, LookupCallback callback)` Lookup a Destination by hash.
    `LookupResult` | `lookupDest2(String name, long maxWait)` Ask the router to lookup a Destination by host name.
    `byte[]` | `receiveMessage(int msgId)` Receive a message that the router has notified the client about, returning the payload.
    `void` | `removeListener(int proto, int port)` removes the specified listener (only)
    `void` | `removeSubsession(I2PSession session)`
    `void` | `reportAbuse(int msgId, int severity)` Instruct the router that the message received was abusive (including how abusive on a 1-100 scale) in the hopes the router can do something to minimize receiving abusive messages like that in the future.
    `void` | `sendBlindingInfo(BlindData bd)`
    `boolean` | `sendMessage(Destination dest, byte[] payload)` Send a new message to the given destination, containing the specified payload, returning true if the router feels confident that the message was delivered.
    `boolean` | `sendMessage(Destination dest, byte[] payload, int offset, int size)` Send a new message to the given destination, containing the specified payload, returning true if the router feels confident that the message was delivered.
    `boolean` | `sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport)` See I2PSessionMuxedImpl for proto/port details.
    `boolean` | `sendMessage(Destination dest, byte[] payload, int offset, int size, int proto, int fromPort, int toPort, SendMessageOptions options)` See I2PSessionMuxedImpl for proto/port details.
    `long` | `sendMessage(Destination dest, byte[] payload, int offset, int size, int proto, int fromPort, int toPort, SendMessageOptions options, SendMessageStatusListener listener)` Send a message and request an asynchronous notification of delivery status.
    `boolean` | `sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent)` End-to-End Crypto is disabled, tags and keys are ignored.
    `boolean` | `sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, int proto, int fromPort, int toPort)` See I2PSessionMuxedImpl for proto/port details.
    `boolean` | `sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire)` End-to-End Crypto is disabled, tags and keys are ignored.
    `boolean` | `sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire, int proto, int fromPort, int toPort)` See I2PSessionMuxedImpl for proto/port details.
    `boolean` | `sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire, int proto, int fromPort, int toPort, int flags)` See I2PSessionMuxedImpl for proto/port details.
    `boolean` | `sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set<SessionTag> tagsSent)` End-to-End Crypto is disabled, tags and keys are ignored! Like sendMessage above, except the key used and the tags sent are exposed to the application.
    `void` | `setSessionListener(I2PSessionListener lsnr)` Instruct the I2PSession where it should send event notifications WARNING: It is recommended that you use a method that specifies the protocol and ports.
    `void` | `updateOptions(Properties options)` Pass updated options to the router.

- - ### Field Detail

    - #### PORT_ANY

          static final int PORT_ANY

      See Also:
        Constant Field Values

    - #### PORT_UNSPECIFIED

          static final int PORT_UNSPECIFIED

      See Also:
        Constant Field Values

    - #### PROTO_ANY

          static final int PROTO_ANY

      See Also:
        Constant Field Values

    - #### PROTO_DATAGRAM

          static final int PROTO_DATAGRAM

      A repliable and signed datagram
      See Also:
        Constant Field Values

    - #### PROTO_DATAGRAM_RAW

          static final int PROTO_DATAGRAM_RAW

      A raw (unsigned, unrepliable) datagram
      See Also:
        Constant Field Values

    - #### PROTO_DATAGRAM2

          static final int PROTO_DATAGRAM2

      A repliable and signed datagram. See Proposal 163 and datagrams/Datagram2
      See Also:
        Constant Field Values

    - #### PROTO_DATAGRAM3

          static final int PROTO_DATAGRAM3

      A repliable but unsigned datagram. See Proposal 163 and datagrams/Datagram3
      See Also:
        Constant Field Values

    - #### PROTO_STREAMING

          static final int PROTO_STREAMING

      See Also:
        Constant Field Values

    - #### PROTO_UNSPECIFIED

          static final int PROTO_UNSPECIFIED

      See Also:
        Constant Field Values

  - ### Method Detail

    - #### addMuxedSessionListener

          void addMuxedSessionListener(I2PSessionMuxedListener l,
                                       int proto,
                                       int port)

      Listen on specified protocol and port, and receive notification of proto, fromPort, and toPort for every message.
      Parameters:
        `proto` - 1-254 or PROTO_ANY (0) for all; 255 disallowed
        `port` - 1-65535 or PORT_ANY (0) for all

    - #### addSessionListener

          void addSessionListener(I2PSessionListener lsnr,
                                  int proto,
                                  int port)

      Listen on specified protocol and port. An existing listener with the same proto and port is replaced. Only the listener with the best match is called back for each message.
      Parameters:
        `proto` - 1-254 or PROTO_ANY (0) for all; recommended: I2PSession.PROTO_STREAMING I2PSession.PROTO_DATAGRAM 255 disallowed
        `port` - 1-65535 or PORT_ANY (0) for all

    - #### addSubsession

          I2PSession addSubsession(InputStream privateKeyStream,
                                   Properties opts)
                            throws I2PSessionException

      Parameters:
        `privateKeyStream` - null for transient, if non-null must have same encryption keys as primary session and different signing keys
        `opts` - subsession options if any, may be null
      Returns:
        a new subsession, non-null
      Throws:
        `I2PSessionException`

    - #### bandwidthLimits

          int[] bandwidthLimits()
                         throws I2PSessionException

      Get the current bandwidth limits. Blocking.
      Throws:
        `I2PSessionException`

    - #### connect

          void connect()
                throws I2PSessionException

      Actually connect the session and start receiving/sending messages. Connecting a primary session will not automatically connect subsessions. Connecting a subsession will automatically connect the primary session if not previously connected.
      Throws:
        `I2PSessionException`

    - #### destroySession

          void destroySession()
                       throws I2PSessionException

      Tear down the session and release any resources.
      Throws:
        `I2PSessionException`

    - #### getMyDestination

          Destination getMyDestination()

      Retrieve the Destination this session serves as the endpoint for. Returns null if no destination is available.

    - #### getOfflineExpiration

          long getOfflineExpiration()

      Get the offline expiration
      Returns:
        Java time (ms) or 0 if not initialized or does not have offline keys

    - #### getOfflineSignature

          Signature getOfflineSignature()

      Returns:
        null on error or if not initialized or does not have offline keys

    - #### getPrivateKey

          SigningPrivateKey getPrivateKey()

      Retrieve the signing SigningPrivateKey associated with the Destination. As of 0.9.38, this will be the transient key if offline signed.

    - #### getRouterVersion

          String getRouterVersion()

      Always valid in RouterContext. Returns null if not yet connected in I2PAppContext.
      Returns:
        null if unknown

    - #### getSubsessions

          List<I2PSession> getSubsessions()

      Returns:
        a list of subsessions, non-null, does not include the primary session

    - #### getTransientSigningPublicKey

          SigningPublicKey getTransientSigningPublicKey()

      Returns:
        null on error or if not initialized or does not have offline keys

    - #### isClosed

          boolean isClosed()

      Have we closed the session?
      Returns:
        true if the session is closed, OR connect() has not been called yet

    - #### isOffline

          boolean isOffline()

      Does this session have offline and transient keys?

    - #### lookupDest

          Destination lookupDest(Hash h)
                          throws I2PSessionException

      Lookup a Destination by Hash. Blocking. Waits a max of 10 seconds by default.
      Throws:
        `I2PSessionException`

    - #### lookupDest

          Destination lookupDest(Hash h,
                                 long maxWait)
                          throws I2PSessionException

      Lookup a Destination by Hash. Blocking.
      Parameters:
        `maxWait` - ms
      Returns:
        null on failure
      Throws:
        `I2PSessionException`

    - #### lookupDest

          LookupResult lookupDest(Hash h,
                                  long maxWait,
                                  LookupCallback callback)
                           throws I2PSessionException

      Lookup a Destination by hostname. Non-blocking. If the result is cached or there is an immediate failure, the result code will be something other than RESULT_DEFERRED, and the callback will NOT be called.
      Parameters:
        `maxWait` - ms
        `callback` - to return the result, non-null
      Returns:
        non-null. If result code is RESULT_DEFERRED, callback will be called later
      Throws:
        `I2PSessionException`

    - #### lookupDest

          Destination lookupDest(String name)
                          throws I2PSessionException

      Ask the router to lookup a Destination by host name. Blocking. Waits a max of 10 seconds by default. This only makes sense for a b32 hostname, OR outside router context. Inside router context, just query the naming service. Outside router context, this does NOT query the context naming service. Do that first if you expect a local addressbook. This will log a warning for non-b32 in router context. Suggested implementation:

            if (name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
                if (session != null)
                    return session.lookup(Hash.create(Base32.decode(name.toLowerCase(Locale.US).substring(0, 52))));
                else
                    return ctx.namingService().lookup(name); // simple session for xxx.b32.i2p handled by naming service (optional if you need lookup w/o an existing session)
            } else if (ctx.isRouterContext()) {
                return ctx.namingService().lookup(name); // hostname from router's naming service
            } else {
                Destination d = ctx.namingService().lookup(name); // local naming svc, optional
                if (d != null)
                    return d;
                if (session != null)
                    return session.lookup(name);
                // simple session (optional if you need lookup w/o an existing session)
                Destination rv = null;
                I2PClient client = new I2PSimpleClient();
                Properties opts = new Properties();
                opts.put(I2PClient.PROP_TCP_HOST, host);
                opts.put(I2PClient.PROP_TCP_PORT, port);
                I2PSession session = null;
                try {
                    session = client.createSession(null, opts);
                    session.connect();
                    rv = session.lookupDest(name);
                } finally {
                    if (session != null)
                        session.destroySession();
                }
                return rv;
            }

      Requires router side to be 0.9.11 or higher. If the router is older, this will return null immediately.
      Throws:
        `I2PSessionException`

    - #### lookupDest

          Destination lookupDest(String name,
                                 long maxWait)
                          throws I2PSessionException

      Ask the router to lookup a Destination by host name. Blocking. See above for details.
      Parameters:
        `maxWait` - ms
      Returns:
        null on failure
      Throws:
        `I2PSessionException`

    - #### lookupDest

          LookupResult lookupDest(String name,
                                  long maxWait,
                                  LookupCallback callback)
                           throws I2PSessionException

      Lookup a Destination by hash. Non-blocking. If the result is cached or there is an immediate failure, the result code will be something other than RESULT_DEFERRED, and the callback will NOT be called.
      Parameters:
        `maxWait` - ms
        `callback` - to return the result, non-null
      Returns:
        non-null. If result code is RESULT_DEFERRED, callback will be called later
      Throws:
        `I2PSessionException`

    - #### lookupDest2

          LookupResult lookupDest2(String name,
                                   long maxWait)
                            throws I2PSessionException

      Ask the router to lookup a Destination by host name. Blocking. See above for details. Same as lookupDest() but with a failure code in the return value
      Parameters:
        `maxWait` - ms
      Returns:
        non-null
      Throws:
        `I2PSessionException`

    - #### receiveMessage

          byte[] receiveMessage(int msgId)
                         throws I2PSessionException

      Receive a message that the router has notified the client about, returning the payload. This may only be called once for a given msgId (until the counter wraps)
      Parameters:
        `msgId` - message to fetch
      Returns:
        unencrypted body of the message, or null if not found
      Throws:
        `I2PSessionException`

    - #### removeListener

          void removeListener(int proto,
                              int port)

      removes the specified listener (only)

    - #### removeSubsession

          void removeSubsession(I2PSession session)

    - #### reportAbuse

          void reportAbuse(int msgId,
                           int severity)
                    throws I2PSessionException

      Instruct the router that the message received was abusive (including how abusive on a 1-100 scale) in the hopes the router can do something to minimize receiving abusive messages like that in the future. Unused. Not fully implemented.
      Parameters:
        `msgId` - message that was abusive (or -1 for not message related)
        `severity` - how abusive
      Throws:
        `I2PSessionException`

    - #### sendBlindingInfo

          void sendBlindingInfo(BlindData bd)
                         throws I2PSessionException

      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload)
                       throws I2PSessionException

      Send a new message to the given destination, containing the specified payload, returning true if the router feels confident that the message was delivered. WARNING: It is recommended that you use a method that specifies the protocol and ports.
      Parameters:
        `dest` - location to send the message
        `payload` - body of the message to be sent (unencrypted)
      Returns:
        whether it was accepted by the router for delivery or not
      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              int offset,
                              int size)
                       throws I2PSessionException

      Send a new message to the given destination, containing the specified payload, returning true if the router feels confident that the message was delivered. WARNING: It is recommended that you use a method that specifies the protocol and ports.
      Parameters:
        `dest` - location to send the message
        `payload` - body of the message to be sent (unencrypted)
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              int proto,
                              int fromport,
                              int toport)
                       throws I2PSessionException

      See I2PSessionMuxedImpl for proto/port details.
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              int offset,
                              int size,
                              int proto,
                              int fromPort,
                              int toPort,
                              SendMessageOptions options)
                       throws I2PSessionException

      See I2PSessionMuxedImpl for proto/port details. See SendMessageOptions for option details.
      Parameters:
        `proto` - 1-254 or 0 for unset; recommended: I2PSession.PROTO_UNSPECIFIED I2PSession.PROTO_STREAMING I2PSession.PROTO_DATAGRAM 255 disallowed
        `fromPort` - 1-65535 or 0 for unset
        `toPort` - 1-65535 or 0 for unset
        `options` - to be passed to the router
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### sendMessage

          long sendMessage(Destination dest,
                           byte[] payload,
                           int offset,
                           int size,
                           int proto,
                           int fromPort,
                           int toPort,
                           SendMessageOptions options,
                           SendMessageStatusListener listener)
                    throws I2PSessionException

      Send a message and request an asynchronous notification of delivery status. Notifications will be delivered at least up to the expiration specified in the options, or 60 seconds if not specified. See I2PSessionMuxedImpl for proto/port details. See SendMessageOptions for option details.
      Parameters:
        `proto` - 1-254 or 0 for unset; recommended: I2PSession.PROTO_UNSPECIFIED I2PSession.PROTO_STREAMING I2PSession.PROTO_DATAGRAM 255 disallowed
        `fromPort` - 1-65535 or 0 for unset
        `toPort` - 1-65535 or 0 for unset
        `options` - to be passed to the router
      Returns:
        the message ID to be used for later notification to the listener
      Throws:
        `I2PSessionException` - on all errors

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              int offset,
                              int size,
                              SessionKey keyUsed,
                              Set<SessionTag> tagsSent)
                       throws I2PSessionException

      End-to-End Crypto is disabled, tags and keys are ignored.
      Parameters:
        `keyUsed` - UNUSED, IGNORED.
        `tagsSent` - UNUSED, IGNORED.
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              int offset,
                              int size,
                              SessionKey keyUsed,
                              Set<SessionTag> tagsSent,
                              int proto,
                              int fromPort,
                              int toPort)
                       throws I2PSessionException

      See I2PSessionMuxedImpl for proto/port details. End-to-End Crypto is disabled, tags and keys are ignored.
      Parameters:
        `keyUsed` - UNUSED, IGNORED.
        `tagsSent` - UNUSED, IGNORED.
        `proto` - 1-254 or 0 for unset; recommended: I2PSession.PROTO_UNSPECIFIED I2PSession.PROTO_STREAMING I2PSession.PROTO_DATAGRAM 255 disallowed
        `fromPort` - 1-65535 or 0 for unset
        `toPort` - 1-65535 or 0 for unset
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              int offset,
                              int size,
                              SessionKey keyUsed,
                              Set<SessionTag> tagsSent,
                              long expire)
                       throws I2PSessionException

      End-to-End Crypto is disabled, tags and keys are ignored.
      Parameters:
        `keyUsed` - UNUSED, IGNORED.
        `tagsSent` - UNUSED, IGNORED.
        `expire` - absolute expiration timestamp, NOT interval from now
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              int offset,
                              int size,
                              SessionKey keyUsed,
                              Set<SessionTag> tagsSent,
                              long expire,
                              int proto,
                              int fromPort,
                              int toPort)
                       throws I2PSessionException

      See I2PSessionMuxedImpl for proto/port details. End-to-End Crypto is disabled, tags and keys are ignored.
      Parameters:
        `keyUsed` - UNUSED, IGNORED.
        `tagsSent` - UNUSED, IGNORED.
        `expire` - absolute expiration timestamp, NOT interval from now
        `proto` - 1-254 or 0 for unset; recommended: I2PSession.PROTO_UNSPECIFIED I2PSession.PROTO_STREAMING I2PSession.PROTO_DATAGRAM 255 disallowed
        `fromPort` - 1-65535 or 0 for unset
        `toPort` - 1-65535 or 0 for unset
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              int offset,
                              int size,
                              SessionKey keyUsed,
                              Set<SessionTag> tagsSent,
                              long expire,
                              int proto,
                              int fromPort,
                              int toPort,
                              int flags)
                       throws I2PSessionException

      See I2PSessionMuxedImpl for proto/port details. End-to-End Crypto is disabled, tags and keys are ignored.
      Parameters:
        `keyUsed` - UNUSED, IGNORED.
        `tagsSent` - UNUSED, IGNORED.
        `expire` - absolute expiration timestamp, NOT interval from now
        `proto` - 1-254 or 0 for unset; recommended: I2PSession.PROTO_UNSPECIFIED I2PSession.PROTO_STREAMING I2PSession.PROTO_DATAGRAM 255 disallowed
        `fromPort` - 1-65535 or 0 for unset
        `toPort` - 1-65535 or 0 for unset
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### sendMessage

          boolean sendMessage(Destination dest,
                              byte[] payload,
                              SessionKey keyUsed,
                              Set<SessionTag> tagsSent)
                       throws I2PSessionException

      End-to-End Crypto is disabled, tags and keys are ignored! Like sendMessage above, except the key used and the tags sent are exposed to the application.

      If some application layer message delivery confirmation is used, rather than i2p's (slow) built in confirmation via guaranteed delivery mode, the application can update the SessionKeyManager, ala:

             SessionKeyManager.getInstance().tagsDelivered(dest.getPublicKey(), keyUsed, tagsSent);

      If an application is using guaranteed delivery mode, this is not useful, but for applications using best effort delivery mode, if they can know with certainty that a message was delivered and can update the SessionKeyManager appropriately, a significant performance boost will occur (subsequent message encryption and decryption will be done via AES and a SessionTag, rather than ElGamal+AES, which is 1000x slower).
      Parameters:
        `dest` - location to send the message
        `payload` - body of the message to be sent (unencrypted)
        `keyUsed` - UNUSED, IGNORED. Session key delivered to the destination for association with the tags sent. This is essentially an output parameter - keyUsed.getData() is ignored during this call, but after the call completes, it will be filled with the bytes of the session key delivered. Typically the key delivered is the same one as the key encrypted with, but not always. If this is null then the key data will not be exposed.
        `tagsSent` - UNUSED, IGNORED. Set of tags delivered to the peer and associated with the keyUsed. This is also an output parameter - the contents of the set is ignored during the call, but afterwards it contains a set of SessionTag objects that were sent along side the given keyUsed.
      Returns:
        success
      Throws:
        `I2PSessionException`

    - #### setSessionListener

          void setSessionListener(I2PSessionListener lsnr)

      Instruct the I2PSession where it should send event notifications WARNING: It is recommended that you use a method that specifies the protocol and ports.
      Parameters:
        `lsnr` - listener to retrieve events

    - #### updateOptions

          void updateOptions(Properties options)

      Pass updated options to the router. Does not remove properties previously present but missing from this options parameter. Fails silently if session is not connected.
      Parameters:
        `options` - non-null