Skip to content

Stack Tool

The Stack Tool is a general purpose command-line tool that can be used to run a Golden Gate stack in a process, and connect the stack's top and bottom ports to UDP sockets so that the stack can communicate with other stacks and/or applications, running on the same host or another host on the network. On macOS, the bottom of the stack can alternatively be connected directly to Bluetooth.
The stacks may be full stacks (ex: DTLS <-> UDP <-> IP <-> Gattlink) or subsets, even single element stacks. This makes it possible to split an entire end-to-end communication chain into separate partial stacks that are assembled into a complete stack by connecting the partial stacks over UDP.

Usage

usage:
  gg-stack-tool [options] hub|node <stack-descriptor-or-command>

where <stack-descriptor-or-command> is either a stack descriptor or a command
string starting with a @ character

options:
  --top [coap] <send_host_ip> <send_port> <receive_port>
    Specify the IP address and port number to connect to the top of the stack (user).
    If the 'coap' option is used, packets sent and received through the top of the stack
    are assumed to be CoAP datagrams.
    (default: 127.0.0.1 9002 9003 as a hub and 127.0.0.1 9003 9002 as a node)

  --top blast <packet-count> <packet-size>
    If <packet-count> is not 0, attach a packet blaster to the top of the stack, with the
    given paket count and packet size, and start blasting, as well as printing stats for
    packets received from a remote blastera. If <packet-count> or <packet-size> is 0,
    don't start blasting, only print stats.

  --top tunnel
    Connect the top of the stack on an IP tunnel (typically only useful for stacks where the
    top of the stack produces/consumes IP packets).

  --bottom <send_host_ip> <send_port> <receive_port>
    Specify the IP address and port number to connect to the bottom of the stack (transport).
    (default: 127.0.0.1 9000 9001 as a hub and 127.0.0.1 9001 9000 as a node)

  --bottom bluetooth <bluetooth-device-id>|scan|node:<advertised-name>
    In the 'hub' role, connect the bottom of the stack directly to a Bluetooth peripheral,
    connecting to the device with ID <bluetooth-device-id> (obtained by scanning).
    Use 'scan' to only scan and display device IDs.
    In the 'node' role, accept connections from a Bluetooth central
    (this is mutually exclusive with the --bottom option above).

  --force-start
    Don't wait for a link up event from the transport before starting the stack (only
    valid when the bottom of the stack is bluetooth).

  --gattlink <max-fragment-size> <rx-window> <tx-window>
    Specify the Gattlink parameters.

  --dtls-key <key-identity>:<key>
    Where <key-identity> is an ASCII string, and <key> is 16 bytes in hex (32 characters)
    For the `hub` role, multiple --dtls-key options can be used to specify a list of
    keys. For the `node` role, only one key can be specified.

  --enable-header-compression
    Enable header compression

  --trace
    Show packets as they are received or sent from the top and bottom sockets.

  --command-port <command_port>
    Receive commands on port <command_port> (default: 7000 for hub, 7001 for node).

  --event-port <event_port>
    Send events on port <event_port> (default: 7100 for hub, 7101 for node).

commands:
    @reset                             : reset the stack
    @dtls-add-key:<key-identity>:<key> : add a DTLS key
    @bt-connect:<uuid>|scan   : connect to a bluetooth device or scan
    @bt-lc-set-mode:slow|fast : set the preferred link controller connection mode

NOTES:
  * Specify a port number of 0 for the send port of the top or bottom to indicate
    that the socket should send to the IP address and port number of the latest received
    packet instead of a fixed address and port.
  * Specify a port number as 0/X, with X non-zero, for the send port of the top, to
    indicate that CoAP requests going to through the top should be sent to port X, but CoAP
    responses should be sent to the port number from which they were received.
  * Specify a port number of 0 for the receive port of the top or bottom to indicate
    that the network stack should pick any available port number.

Bluetooth

On macOS, the tool can interface directly with the operating system's Bluetooth stack.

Bluetooth as a Hub

The --bottom bluetooth <bluetooth-device-id> option may be used to connect to a bluetooth device running a compatible stack. <bluetooth-device-id> is a macOS-assigned peripheral UUID. To obtain the bluetooth device ID for a specific device, first run the tool with the option --bottom bluetooth scan and look for the device IDs printed on the console. Once you have found the device you are looking for, re-run the tool with the actual bluetooth device ID you want to connect to.

Bluetooth as a Node

The --bottom bluetooth node:<bluetooth-device-name> option may be used to advertise bluetooth services as a Node.

Tip

In order to keep the console output reasonably quiet, it is recommended to limit the logging level to INFO, which can be done this way:

$ export "GG_LOG_CONFIG=plist:.level=INFO"

or to trace the operations of the bluetooth transport:

$ export "GG_LOG_CONFIG=plist:gg.xp.app.stack-tool.core-bluetooth.level=ALL;.ConsoleHandler.filter=4;.level=INFO"

Examples

In the following examples, we setup stacks or partial stacks connected together so that UDP packets sent to port 5680 are sent through the stacks and come out at the end as a UDP packet sent to localhost (127.0.0.1) on port 5683. This way, we can use a regular CoAP server listening on port 5683, and a regular CoAP client that sends request to the localhost (127.0.0.1) on port 5680, which will be forwarded through the stacks to the sever.

Adding the tools to your PATH

In the following examples, we assume that the directories where the command line tools are build have been added your PATH. Alternatively, you can use the full path to the tool's executable instead of just the executable name.

CoAP Client And Server Through A Stack

In these examples, we run two or more stack tool instances (in separate shell processes), configured such that one of the stacks receives packets at its top, on port 5680, from a CoAP client, and communicates with another stack, itself possibly connected to another stack, and so on, until a last stack that sends packets to a CoAP server on port 5683.

Network topology:

 +--------+            +------------+   |            |            +--------+
 | CoAP   |---[5680]-->|            |-->| any number |---[5683]-->| CoAP   |
 | Client |            | Stack Tool |   | of Stack   |..          | Server |
 |        |<--[any ]---|            |<--| Tool       |<--[any ]---|        |
 +--------+            +------------+   | processes  |            +--------+

In each case, once the stacks are running, run the Python CoAP server from CoAPthon

$ coapserver.py

And then run the CoAP client using the coap NodeJS tool from coap-cli

$ coap coap://127.0.0.1:5680/big

You should see the CoAP response printed on the console.

$ coap coap://127.0.0.1:5680/big
(2.05)  Lorem ipsum dolor sit amet, ...

Configuration 1

Simple pair of complete stacks connect to each other on the bottom side. (run each of the following commands in a separate shell):

$ gg-stack-tool --top coap 127.0.0.1 5683 0 hub DSNG
$ gg-stack-tool --top coap 127.0.0.1 0 5680 node DSNG

Configuration 2

Completely deconstructed stacks (each stack runs a single layer of a complete stack, so it is like having a stack where each layer runs in a separate process).

Advanced example

This is an advanced example, intended to illustrate that you can combine multiple stacks together, but in practice you will typically use just one stack on each machine.

Run each of the following commands in a separate shell):

$ gg-stack-tool --top coap 127.0.0.1 5683 0 --bottom 127.0.0.1 9009 9008 --trace hub D
$ gg-stack-tool --top 127.0.0.1 9008 9009 --bottom 127.0.0.1 9007 9006 --trace --command-port 7001 hub SN
$ gg-stack-tool --top 127.0.0.1 9006 9007 --bottom 127.0.0.1 9004 9005 --trace --command-port 7002 hub G
$ gg-stack-tool --top 127.0.0.1 9002 9003 --bottom 127.0.0.1 9005 9004 --trace --command-port 7003 node G
$ gg-stack-tool --top 127.0.0.1 9000 9001 --bottom 127.0.0.1 9003 9002 --trace --command-port 7004 node SN
$ gg-stack-tool --top coap 127.0.0.1 0 5680 --bottom 127.0.0.1 9001 9000 --command-port 7005 --trace node D

Bluetooth Examples

These examples are only available on the mac, not Linux, because the stack tool doesn't yet have native Bluetooth support on Linux desktops. On the mac, the OS assigns a unique device ID to each Bluetooth device it can connect to (instead of exposing the device's Bluetooth address). So the first step is to use the stack tool to scan for devices, which will print on the console a list of compatible Bluetooth devices, along with their OS-assigned device ID. Those device IDs can then be used to connect.

Scanning

Run

$ gg-stack-tool --bottom bluetooth connect hub DSNG

If there is a compatible device advertising, you should see on the console something like (see the tip above about setting your GG_LOG_CONFIG environment variable to avoid having too many log lines clutter the console output):

Bluetooth Scan: gg-peripheral - ID = DB147848-D227-43A8-A7A7-3AF2530BABC5 RSSI = -34

In this example, we see a device advertising as gg-peripheral for which the OS has assigned ID DB147848-D227-43A8-A7A7-3AF2530BABC5.

Bluetooth Hub Example

In this example, we connect to a specific device over Bluetooth (device ID DB147848-D227-43A8-A7A7-3AF2530BABC5 in this example) and we start a stack. The top of the stack is configured to proxy packets on port 5683, so any CoAP client targeting the macOS host will end up being proxy'ed to the device.

 +--------+            +------------+   |           |      +-----------+
 | CoAP   |---[5683]-->|            |-->|           |----->| GG Device |
 | Client |            | Stack Tool |   | Bluetooth |      | with CoAP |
 |        |<--[any ]---|            |<--|           |<-----| server    |
 +--------+            +------------+   |           |      +-----------+

Run:

$ gg-stack-tool --trace --top coap 127.0.0.1 0 5683 --bottom bluetooth DB147848-D227-43A8-A7A7-3AF2530BABC5 hub DSNG

If the device you are connecting to hosts a CoAP server with a /helloworld resource (as would be the case for the Pylon gg-peripheral app running on a Nordic board), you can try a CoAP request like:

$ gg-coap-client get coap://127.0.0.1/helloworld

You should see:

=== Received response block, offset=0:
  code = 2.05
  token = 41A73AF1
  option 12 [Content-Format] (uint): 0
  payload size = 18
  payload:
  0000: Hello CoAP clien    48656C6C6F20436F415020636C69656E
  0016: t!                  7421                            
### Last block, we're done!
Hello CoAP client!

Bluetooth Node Example

In this example, we start the stack and advertise bluetooth services under the name 'Jiji'. The stack is configured with DTLS, but no key other than the default bootstrap key. The top port is also configured to send CoAP requests out to a local CoAP server that is listening on port 6683.

 +--------+
 | CoAP   |
 | Server |<--+
 |        |   |
 +--------+   |
              |
 +--------+   +-[6683]--->+------------+   |           |      +-----------+
 | CoAP   |-----[5683]--->|            |-->|           |----->| GG Device |
 | Client |               | Stack Tool |   | Bluetooth |      | with CoAP |
 |        |<----[any ]----|            |<--|           |<-----| server    |
 +--------+               +------------+   |           |      +-----------+

Run:

$ gg-stack-tool --trace --bottom bluetooth node:Jiji --top 127.0.0.1 0/6683 5683 node DSNG