On this page:
4.1 event-relay
event-relay
4.2 tcp-bare
tcp-driver
tcp
4.2.1 TCP channels
tcp-channel
4.2.2 TCP addresses
tcp-address
tcp-handle
tcp-listener
4.2.3 Opening an outbound connection
4.2.4 Accepting inbound connections
4.2.5 Receiving data
4.2.6 Sending data
4.3 timer
4.4 udp
6.3.90.900

4 Drivers

4.1 event-relay

 (require marketplace/drivers/event-relay)
  package: marketplace

procedure

(event-relay self-id)  Spawn

  self-id : Symbol
Lets processes in some nested VM interact with the outside world using ground-vm-level event-based subscriptions.

Returns a spawn which starts an event-relay process with debug-name `(event-relay ,self-id).
The relay process observes subscriptions matching the topic-pattern (cons (? evt?) _), and when one appears, constructs an analogous one using at-meta-level to connect to the next VM down the stack. Messages from the meta-level will be relayed up to the current level. When the subscription disappears, the relay withdraws the subscription at the meta-level as well.

4.2 tcp-bare

 (require marketplace/drivers/tcp-bare)
  package: marketplace
This module is included by default in programs using #lang marketplace; see Using #lang marketplace and friends for information on other language variants.

procedure

(tcp-driver)  Spawn

Returns a spawn action which starts a TCP driver. The TCP driver should run either directly in a ground VM, or in a nested VM with a running event-relay.

value

tcp : Spawn

A pre-made spawn action equivalent to (tcp-driver).

4.2.1 TCP channels

struct

(struct tcp-channel (source destination subpacket)
    #:prefab)
  source : (or/c tcp-address? tcp-handle? tcp-listener?)
  destination : (or/c tcp-address? tcp-handle? tcp-listener?)
  subpacket : (or/c eof-object? bytes?)
A TCP channel represents a section of a unidirectional TCP flow appearing on our local "subnet" of the full TCP network, complete with source, destination and subpacket. Each TCP connection has two such flows: one inbound (remote-to-local) bytestream, and one outbound (local-to-remote) bytestream.

Packets carried by tcp-channel structures are either end-of-file objects or raw binary data represented as Racket byte vectors.

4.2.2 TCP addresses

A TCP address describes one end of a TCP connection. It can be either

struct

(struct tcp-address (host port)
    #:prefab)
  host : string?
  port : (integer-in 0 65535)
Describes a remote half-connection. The host part is to be a string containing either a hostname (e.g. "localhost") or an ASCII representation of an IP address (e.g. "127.0.0.1").

struct

(struct tcp-handle (id)
    #:prefab)
  id : any/c
Describes a local half-connection with a kernel-assigned port number. The port number is not directly accessible; the id is used as a local name for whichever underlying port number ends up being used.

The id must be chosen carefully: it is scoped to the local VM, i.e. shared between processes in that VM, so processes must make sure not to accidentally clash in handle ID selection. They are also used in tcp-channel to mean a specific instance of a TCP connection, so if you are likely to want to reconnect individual flows, use different values for id.

struct

(struct tcp-listener (port)
    #:prefab)
  port : (integer-in 0 65535)
Describes a local half-connection with a user-assigned port number. Use this to describe server sockets.

4.2.3 Opening an outbound connection

Choose a tcp-handle, and then create endpoints as follows:

(let ((local (tcp-handle 'some-unique-value))
      (remote (tcp-address "the.remote.host.example.com" 5999)))
  (transition/no-state
   (publisher (tcp-channel local remote ?))
   (subscriber (tcp-channel remote local ?)
     (on-message
      [(tcp-channel _ _ (? eof-object?))
       ; Handle a received end-of-file object
       (transition ...)]
      [(tcp-channel _ _ (? bytes? data))
       ; Handle received data
       (transition ...)]))))

The TCP driver will automatically create an outbound connection in response to the presence of the endpoints. When the endpoints are deleted (or the process exits), the TCP driver will notice the absence and will close the underlying TCP socket.

For a complete example, see TCP chat client.

4.2.4 Accepting inbound connections

Choose a port number, and then create an observer endpoint as follows:

(observe-publishers (tcp-channel ? (tcp-listener 5999) ?)
  (match-conversation (tcp-channel them us _)
    (on-presence (spawn (chat-session them us)))))

The use of observe-publishers here indicates that this endpoint isn’t actually interested in exchanging any TCP data; instead, it is monitoring demand for such exchanges. The TCP driver uses the unusual 'everything InterestType to monitor the presence of 'observers, and creates listening TCP server sockets in response. When a connection comes in, the TCP driver spawns a manager process which offers regular 'participant endpoints for communicating on the newly-arrived socket.

To illustrate the code for handling a newly-arrived connection,

(define (chat-session them us)
  (transition/no-state
   (subscriber (tcp-channel them us ?)
     (on-absence (quit))
     (on-message [(tcp-channel _ _ (? bytes? data))
                  ; Handle incoming data
                  (transition ...)]))))
4.2.5 Receiving data

TCP-related messages will be of the form

(tcp-channel remote-address local-address subpacket)

where the subpacket is either eof or a bytes?.

4.2.6 Sending data

Send data with

(send-message (tcp-channel local-address remote-address subpacket))

where, as for receiving data, the subpacket is either eof or a bytes?.

4.3 timer

For examples of the use of the timer driver, see uses of set-timer and timer-expired in the Marketplace-based DNS resolver.

4.4 udp

For examples of the use of the UDP driver, see uses of udp-packet etc. in the Marketplace-based DNS resolver.