Skip navigation

# SAM

Specified below is a simple client protocol for interacting with I2P based on discussions between human and jrandom.

    ----------------------------------------------------------------------
    Simple Anonymous Messaging (SAM version 2.0)
    ----------------------------------------------------------------------
    Client application talks to SAM bridge, which deals with
    all of the I2P functionality (using the ministreaming
    lib for virtual streams, or I2CP directly for async messages).

    All client<-->SAM bridge communication is unencrypted and
    unauthenticated over a single TCP socket.  Access to the SAM
    bridge should be protected through firewalls or other means
    (perhaps the bridge may have ACLs on what IPs it accepts
    connections from).

    All of these SAM messages are sent on a single line in plain ASCII,
    terminated by the newline character (\n).  The formatting shown
    below is merely for readability, and while the first two words in
    each message must stay in their specific order, the ordering of
    the key=value pairs can change (e.g. "ONE TWO A=B C=D" or
    "ONE TWO C=D A=B" are both perfectly valid constructions).  In
    addition, the protocol is case-sensitive.

    Communication can take three distinct forms:
    * Virtual streams
    * Repliable datagrams (messages with a FROM field)
    * Anonymous datagrams (raw anonymous messages)

    ----------------------------------------------------------------------
    SAM connection handshake
    ----------------------------------------------------------------------
    No SAM communication can occur until after the client and bridge have
    agreed on a protocol version, which is done by the client sending
    a HELLO and the bridge sending a HELLO REPLY:

      HELLO VERSION MIN=$min MAX=$max

    and

      HELLO REPLY RESULT=$result VERSION=2.0

    In order to force protocol version 2.0, the values of $min and $max
    must be "2.0".

    The RESULT value may be one of:

        OK
        NOVERSION

    ----------------------------------------------------------------------
    SAM sessions
    ----------------------------------------------------------------------
    A SAM session is created by a client opening a socket to the SAM
    bridge, operating a handshake, and sending a SESSION CREATE message,
    and the session terminates when the socket is disconnected.

    Each I2P Destination can only be used for one SAM session at a time,
    and can only use one of those forms (messages received through other
    forms are dropped).

    The SESSION CREATE message sent by the client to the bridge is as
    follows:

      SESSION CREATE
              STYLE={STREAM,DATAGRAM,RAW}
              DESTINATION={$name,TRANSIENT}
              [DIRECTION={BOTH,RECEIVE,CREATE}]
              [option=value]*

    DESTINATION specifies what destination should be used for
    sending and receiving messages/streams.  If a $name is given, the
    SAM bridge looks through its own local storage for an associated
    destination (and private key).  If no association exists matching
    that name, it creates a new one.  If the destination is specified
    as TRANSIENT, it always creates a new one.

    The DIRECTION can be specified for STREAM sessions, instructing
    the bridge that the client will either be creating or receiving
    streams, or both.  If this is not specified, BOTH will be assumed.
    Attempting to create an outbound stream when DIRECTION=RECEIVE
    should result in an error, and incoming streams when
    DIRECTION=CREATE should be ignored.

    Additional options given should be fed into the I2P session
    configuration if not interpreted by the SAM bridge (e.g.
    "tunnels.depthInbound=0"). These options are documented below.

    The SAM bridge itself should already be configured with what router
    it should communicate over I2P through (though if need be there may
    be a way to provide an override, e.g. i2cp.tcp.host=localhost and
    i2cp.tcp.port=7654).

    After receiving the session create message, the SAM bridge will reply
    with a session status message, as follows:

      SESSION STATUS
              RESULT=$result
              DESTINATION={$name,TRANSIENT}
              [MESSAGE=...]

    The RESULT value may be one of:

        OK
        DUPLICATED_DEST
        I2P_ERROR
        INVALID_KEY

    If it's not OK, the MESSAGE should contain human-readable information
    as to why the session could not be created.

    ----------------------------------------------------------------------
    SAM virtual streams
    ----------------------------------------------------------------------
    Virtual streams are guaranteed to be sent reliably and in order, with
    failure and success notification as soon as it is available.

    After establishing the session with STYLE=STREAM, both the client
    and the SAM bridge may asynchronously send various messages back and
    forth to manage the streams, as listed below:

      STREAM CONNECT
             ID=$id
             DESTINATION=$base64key

    This establishes a new virtual connection from the local destination
    to the specified peer, marking it with the session-scoped unique ID.
    The unique ID is an ASCII base 10 integer from 1 through (2^31-1).
    The SAM bridge replies to this with a stream status message:

      STREAM STATUS
             RESULT=$result
             ID=$id
             [MESSAGE=...]

    The RESULT value may be one of:

        OK
        CANT_REACH_PEER
        I2P_ERROR
        INVALID_KEY
        TIMEOUT

    If the RESULT is OK, the destination specified is up and authorized
    the connection; if the connection was not possible (timeout, etc),
    RESULT will contain the appropriate error value (accompanied by an
    optional human-readable MESSAGE).

    On the receiving end, the SAM bridge simply notifies the client as
    follows:

      STREAM CONNECTED
             DESTINATION=$base64key
             ID=$id

    This tells the client that the given destination has created a virtual
    connection with them.  The following data stream will be marked with
    the given unique ID, that is an ASCII base 10 integer from -1 through
    -(2^31-1).

    When the client wants to send data on the virtual connection, they
    do so as follows:

      STREAM SEND
             ID=$id
             SIZE=$numBytes\n[$numBytes of data]

    This asks the SAM bridge to add the specified data to the buffer
    being sent to the peer over the virtual connection.  The send size
    $numBytes is how many 8bit bytes are included after the newline,
    which may be 1 through 32768 (32KB).

    The SAM bridge immediately replies with:

      STREAM SEND
             ID=$id
             RESULT=$result
             STATE=$bufferState

      where $bufferState can be :
              - BUFFER_FULL : SAM's buffer has 32 or more KB of data
                              to send, and subsequent SEND requests
                              will fail ;
              - READY : SAM's buffer is not full, and the next SEND
                        request is granted to be successful.

      and $result is one of :
              - OK     : the data has been buffered successfully
              - FAILED : the buffer was full, no data has been buffered

    If the SAM bridge replied with BUFFER_FULL, it will send another
    message as soon as its buffer is available again :

      STREAM READY_TO_SEND ID=$id

    When the result is OK, the SAM bridge will then do its best to deliver
    the message as quickly and efficiently as possible, perhaps buffering
    multiple SEND messages together.  If there is an error delivering the
    data, or if the remote side closes the connection, the SAM bridge will
    tell the client:

      STREAM CLOSED
             RESULT=$result
             ID=$id
             [MESSAGE=...]

    The RESULT value may be one of:

        OK
        CANT_REACH_PEER
        I2P_ERROR
        PEER_NOT_FOUND
        TIMEOUT

    If the connection has been cleanly closed by the other peer, $result
    is set to OK.  If $result is not OK, MESSAGE may convey a descriptive
    message, such as "peer unreachable", etc.  Whenever a client would
    like to close the connection, they send the SAM bridge the close
    message:

      STREAM CLOSE
             ID=$id

    The bridge then cleans up what it needs to and discards that ID - no
    further messages can be sent or received on it.

    For the other side of the communication, whenever the peer has sent
    some data and it is available for the client, the SAM bridge will
    promptly deliver it:

      STREAM RECEIVED
             ID=$id
             SIZE=$numBytes\n[$numBytes of data]

    With SAM version 2.0, though, the client has first to tell the SAM
    bridge how much incoming data is allowed for the whole session, by
    sending a message :

      STREAM RECEIVE
             ID=$id
             LIMIT=$limit\n

      where $limit can be :

          - NONE : the SAM bridge will keep on listening and deliver
                   incoming data (same behaviour as in version 1.0)

          - an integer (less than 2^64) : the number of received bytes
                   after which the SAM bridge will stop listening on
                   the incoming stream.

                   Whenever the client is ready to accept more bytes
                   from the stream, it has to send such a message again,
                   with a greater $limit.

    The client has to send such STREAM RECEIVE messages after the
    connection to the peer has been established, i.e. after the client
    has received a "STREAM CONNECTED" or a "STREAM STATUS RESULT=OK"
    from the SAM bridge.

    All streams are implicitly closed by the connection between the SAM
    bridge and the client being dropped.

    ----------------------------------------------------------------------
    SAM repliable datagrams
    ----------------------------------------------------------------------
    While I2P doesn't inherently contain a FROM address, for ease of use
    an additional layer is provided as repliable datagrams - unordered
    and unreliable messages of up to 31KB in size that include a FROM
    address (leaving up to 1KB for header material).  This FROM address
    is authenticated internally by SAM (making use of the destination's
    signing key to verify the source) and includes replay prevention.

    After establishing a SAM session with STYLE=DATAGRAM, the client can
    send the SAM bridge:

      DATAGRAM SEND
               DESTINATION=$base64key
               SIZE=$numBytes\n[$numBytes of data]

    When a datagram arrives, the bridge delivers it to the client via:

      DATAGRAM RECEIVED
               DESTINATION=$base64key
               SIZE=$numBytes\n[$numBytes of data]

    The SAM bridge never exposes to the client the authentication headers
    or other fields, merely the data that the sender provided.  This
    continues until the session is closed (by the client dropping the
    connection).

    ----------------------------------------------------------------------
    SAM anonymous datagrams
    ----------------------------------------------------------------------
    Squeezing the most out of I2P's bandwidth, SAM allows clients to send
    and receive anonymous datagrams, leaving authentication and reply
    information up to the client themselves.  These datagrams are
    unreliable and unordered, and may be up to 32KB in size.

    After establishing a SAM session with STYLE=RAW, the client can
    send the SAM bridge:

      RAW SEND
          DESTINATION=$base64key
          SIZE=$numBytes\n[$numBytes of data]

    When a raw datagram arrives, the bridge delivers it to the client
    via:

      RAW RECEIVED
          SIZE=$numBytes\n[$numBytes of data]

    ----------------------------------------------------------------------
    SAM utility functionality
    ----------------------------------------------------------------------
    The following message can be used by the client to query the SAM
    bridge for name resolution:

     NAMING LOOKUP
            NAME=$name

    which is answered by

     NAMING REPLY
            RESULT=$result
            NAME=$name
            [VALUE=$base64key]
            [MESSAGE=$message]

    The RESULT value may be one of:

        OK
        INVALID_KEY
        KEY_NOT_FOUND

    If NAME=ME, then the reply will contain the base64key used by the
    current session (useful if you're using a TRANSIENT one).  If $result
    is not OK, MESSAGE may convey a descriptive message, such as "bad
    format", etc.

    Public and private base64 keys can be generated using the following
    message:

     DEST GENERATE

    which is answered by

     DEST REPLY
          PUB=$pubkey
          PRIV=$privkey

    ----------------------------------------------------------------------
    RESULT values
    ----------------------------------------------------------------------
    These are the values that can be carried by the RESULT field, with
    their meaning:

     OK              Operation completed succesfully
     CANT_REACH_PEER The peer exists, but cannot be reached
     DUPLICATED_DEST The specified Destination is already in use
     I2P_ERROR       A generic I2P error (e.g. I2CP disconnection, etc.)
     INVALID_KEY     The specified key is not valid (bad format, etc.)
     KEY_NOT_FOUND   The naming system can't resolve the given name
     PEER_NOT_FOUND  The peer cannot be found on the network
     TIMEOUT         Timeout while waiting for an event (e.g. peer answer)

    ----------------------------------------------------------------------
    Tunnel Pool Options
    ----------------------------------------------------------------------

    These options can be passed in as name=value pairs at the end of a
    SAM SESSION CREATE line.

     inbound.nickname            - Name shows up in I2P router console.
     inbound.quantity            - Number of tunnels, default 2.
     inbound.backupQuantity      - Number of backup tunnels, default 0.
     inbound.rebuildPeriod       - Tunnels are rebuilt X ms before
                                   expiration, default 60*1000.
     inbound.duration            - Tunnels last X ms, default 10*60*1000.
     inbound.length              - Depth of tunnels, default 2.
     inbound.lengthVariance      - If negative, randomly skews from
                                   (length - variance) to
                                   (length + variance).  If positive, from
                                   length to (length + var), inclusive.
                                   Default -1.
     inbound.allowZeroHop        - Zero hop allowed?  Default "true".
     outbound.*                  - Same properties as inbound.
     i2p.streaming.connectDelay  - If 0, connect ASAP.  If positive, wait
                                   until X ms have passed or output stream
                                   is flushed or buffer fills.  Default 0.
     i2p.streaming.maxWindowSize - Max window size, default 64.

    ----------------------------------------------------------------------
    Client library implementations:
    ----------------------------------------------------------------------
     C/C++:  libSAM: http://www.innographx.com/mpc/libsam/ or i2p/sam/c/
     Python: Python/I2P: http://dev.i2p.net/contrib/apps/sam/python/index.html
     Others: See apps/sam/ in I2P CVS.