# `nupp.io.net`
`nupp.io.net` is the network as bytes: a listener, the connections it accepts,
and connections this process opens itself.
```nupp
local listener = assert(nupp.io.net.listen({host = "127.0.0.1", port = 0}))
local stream = assert(listener:accept())
print(assert(stream:read(5)))
stream:close()
listener:close()
```
A connection reads and writes through the `Reader` and `Writer` contracts on
`nupp.io`, so a parser written against byte I/O reads a socket without knowing
it has one. A read answers bytes, suspends while none have arrived, or answers
empty because the peer closed its sending half; empty is only ever the end.
A listener and a connection are owners. See
[ownership.md](../../../../learn/runtime/ownership/borrowing/index.html) for the contract they are handed
out under.
## Types
### `Address` _type_
```nupp
type Address = {
--- The peer's address, as a literal.
host: string,
--- The peer's port.
port: integer
}
```
Where a datagram came from, and where one may be sent.
### `ConnectOptions` _type_
```nupp
type net.ConnectOptions = {
--- The peer to reach, as a name or an address literal. A name is resolved
--- off this frame. Given with `port`, and not with `path`.
host: string?,
--- The peer's port.
port: integer?,
--- A filesystem name to reach instead, for a Unix domain socket. Nothing is
--- resolved for one, so a connect to a path starts at the handshake.
path: string?,
--- The most bytes this connection may hold unsent before `write` waits.
--- Defaults to one mebibyte.
sendHighWater: integer?,
--- How long the connect may take, resolution included, before it gives up.
--- Defaults to thirty seconds.
---
--- There is no way to ask for no deadline at all. A connect that waits
--- forever is a hang somebody eventually reports as a bug, and a peer that
--- accepts a packet and then says nothing is a normal thing on a network
--- rather than an unusual one.
timeoutMs: integer?
}
```
How a connection is opened.
### `Datagram` _record_
```nupp
record net.Datagram is nupp.Closeable
function port(self): integer end
function isReleased(self): boolean end
function receiveFrom(self, exclusive destination: Buffer, maximum: integer): (net.Message?, string?) end
function sendTo(self, address: net.Address, bytes: string): (boolean, string?) end
function setBroadcast(self, enable: boolean): (boolean, string?) end
function setMulticastTTL(self, ttl: integer): (boolean, string?) end
function setMulticastLoop(self, enable: boolean): (boolean, string?) end
function joinMulticast(self, group: string, interfaceAddress: string?): (boolean, string?) end
function leaveMulticast(self, group: string, interfaceAddress: string?): (boolean, string?) end
function close(takes self): nil end
end
```
A datagram socket.
A message transport rather than a stream one: nothing here buffers arrivals
into a run, because the boundaries between them are the protocol.
#### Methods
##### `port`
```nupp
port: function port(self): integer
```
The port this socket actually bound.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
##### `isReleased`
```nupp
isReleased: function isReleased(self): boolean
```
Whether this socket has been released.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
##### `receiveFrom`
```nupp
receiveFrom: function receiveFrom(self, exclusive destination: Buffer, maximum: integer): net.Message?, string?
```
Takes the next datagram into `destination`, suspending until one
arrives.
A zero-length answer is an empty datagram and not an absence: several
protocols use them as keepalives, and a receive that could not tell them
from a quiet socket would make a live peer look like silence.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this socket |
| `exclusive destination` | `Buffer` | where the bytes go |
| `maximum` | `integer` | the most bytes to take from one datagram |
###### Returns
| Type | Description |
| --- | --- |
| `net.Message?` | what the message was, or nil when the socket failed |
| `string?` | why there is none, when unsuccessful |
###### Raises
- when maximum is not a positive integer
##### `sendTo`
```nupp
sendTo: function sendTo(self, address: net.Address, bytes: string): boolean, string?
```
Sends one datagram.
Answers whether the platform took it, which is not a delivery receipt and
never could be: a datagram that goes is a datagram that may still not
arrive, and a protocol that needs to know says so in the protocol.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this socket |
| `address` | `net.Address` | where to send it |
| `bytes` | `string` | what to send |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether the platform took it |
| `string?` | why it did not, when unsuccessful |
##### `setBroadcast`
```nupp
setBroadcast: function setBroadcast(self, enable: boolean): boolean, string?
```
Allows sending to a broadcast address.
Refused by default by the platform, so a program that means to broadcast
has to say so rather than discover it works.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `enable` | `boolean` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
| `string?` | |
##### `setMulticastTTL`
```nupp
setMulticastTTL: function setMulticastTTL(self, ttl: integer): boolean, string?
```
How many hops a multicast datagram may take.
One keeps it on the local segment, which is what discovery on a LAN
wants and what the platform starts at.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `ttl` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
| `string?` | |
###### Raises
- when the hop limit is not 1 through 255
##### `setMulticastLoop`
```nupp
setMulticastLoop: function setMulticastLoop(self, enable: boolean): boolean, string?
```
Whether this socket also receives what it sends to a group it joined.
Off is usually what is wanted: a discovery protocol that answers its own
announcements is the first bug somebody writes with one.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `enable` | `boolean` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
| `string?` | |
##### `joinMulticast`
```nupp
joinMulticast: function joinMulticast(self, group: string, interfaceAddress: string?): boolean, string?
```
Joins a multicast group.
`interfaceAddress` names which of this machine's addresses to join on.
On a machine with more than one, the platform's own choice is rarely the
one wanted, which is why it is asked for rather than assumed.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `group` | `string` | |
| `interfaceAddress` | `string?` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
| `string?` | |
##### `leaveMulticast`
```nupp
leaveMulticast: function leaveMulticast(self, group: string, interfaceAddress: string?): boolean, string?
```
Leaves a multicast group.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `group` | `string` | |
| `interfaceAddress` | `string?` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
| `string?` | |
##### `close`
```nupp
close: function close(takes self): nil
```
Releases the socket. Idempotent, and terminal.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `takes self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
### `DatagramOptions` _type_
```nupp
type net.DatagramOptions = {
--- The address to bind, as an IPv4 or IPv6 literal.
host: string,
--- The port to bind, or zero to let the platform choose one.
port: integer,
--- Whether to ask for load-balancing port reuse, so that a socket per lane
--- shares one port. Refused where the platform's semantics are not load
--- balancing rather than quietly degraded.
reusePort: boolean?
}
```
How a datagram socket is opened.
### `DirectionView` _record_
```nupp
record net.DirectionView is Reader, Writer
function read(self, count: integer): (string?, string?) end
function readSpan(self, exclusive destination: span.Writable): (integer?, string?) end
function readInto(self, exclusive destination: Buffer, offset: integer?, count: integer?): (integer?, string?) end
function transferTo(self, exclusive destination: Writer): (integer?, string?) end
function write(exclusive self, bytes: string): (boolean, string?) end
function writeSpan(exclusive self, borrows source: span.ByteSpan): (integer?, string?) end
function flush(self): (boolean, string?) end
function close(takes self): nil end
end
```
A borrowed view of one direction of a connection.
Closing one ends that direction rather than the connection: the writing view
half-closes, and the reading view stops this side reading. Neither is the
cleanup obligation, which stays with the connection.
#### Methods
##### `read`
```nupp
read: function read(self, count: integer): string?, string?
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `count` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `string?` | |
| `string?` | |
###### Raises
- when count is not a positive integer
##### `readSpan`
```nupp
readSpan: function readSpan(self, exclusive destination: span.Writable): integer?, string?
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `exclusive destination` | `span.Writable\` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer?` | |
| `string?` | |
###### Raises
- when the destination is empty
##### `readInto`
```nupp
readInto: function readInto(self, exclusive destination: Buffer, offset: integer?, count: integer?): integer?, string?
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `exclusive destination` | `Buffer` | |
| `offset` | `integer?` | |
| `count` | `integer?` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer?` | |
| `string?` | |
###### Raises
- when count is not a positive integer
##### `transferTo`
```nupp
transferTo: function transferTo(self, exclusive destination: Writer): integer?, string?
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
| `exclusive destination` | `Writer` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer?` | |
| `string?` | |
##### `write`
```nupp
write: function write(exclusive self, bytes: string): boolean, string?
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `exclusive self` | `any` | |
| `bytes` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
| `string?` | |
##### `writeSpan`
```nupp
writeSpan: function writeSpan(exclusive self, borrows source: span.ByteSpan): integer?, string?
```
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `exclusive self` | `any` | |
| `borrows source` | `span.ByteSpan` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer?` | |
| `string?` | |
##### `flush`
```nupp
flush: function flush(self): boolean, string?
```
Waits until nothing this view wrote is still held by the platform.
The same queue the connection has, because it is the same connection.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
| `string?` | |
##### `close`
```nupp
close: function close(takes self): nil
```
Ends this direction and leaves the connection alone.
The writing view half-closes, so the peer sees end of stream. The reading
view stops this side reading, which is deliberately not the platform's
receive shutdown: its behaviour varies enough between stacks to be worth
not depending on.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `takes self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
### `Listener` _record_
```nupp
record net.Listener is nupp.Closeable
function port(self): integer end
function isReleased(self): boolean end
function accept(self): (affine(net.Stream)?, string?) end
function close(takes self): nil end
end
```
A listening socket.
#### Methods
##### `port`
```nupp
port: function port(self): integer
```
The port this listener actually bound, which is what a caller who asked
for zero needs.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
##### `isReleased`
```nupp
isReleased: function isReleased(self): boolean
```
Whether this listener has been released.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
##### `accept`
```nupp
accept: function accept(self): affine(net.Stream)?, string?
```
Takes the next connection, suspending until one arrives.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this listener |
###### Returns
| Type | Description |
| --- | --- |
| `affine(net.Stream)?` | the connection, which the caller owns and must close |
| `string?` | why there is none, when the listener failed |
##### `close`
```nupp
close: function close(takes self): nil
```
Releases the listener and every connection it accepted that nobody took.
Idempotent, and terminal.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `takes self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
### `ListenOptions` _type_
```nupp
type net.ListenOptions = {
--- The address to bind, as an IPv4 or IPv6 literal. A name is not resolved
--- here, because a listener binds an interface rather than reaching a peer.
---
--- Given with `port`, and not with `path`: a listener binds an address or a
--- filesystem name, and naming both says two different things at once.
host: string?,
--- The port to bind, or zero to let the platform choose one. `Listener.port`
--- answers which was chosen.
port: integer?,
--- A filesystem name to bind instead, for a Unix domain socket.
---
--- The name is not removed when the listener closes. A caller that binds a
--- path owns that path, and unlinking a file this process may not have
--- created is not a transport's decision to make.
path: string?,
--- How many connections the platform may hold before this process accepts
--- them, or nil for the platform's usual depth.
backlog: integer?,
--- Whether to ask for load-balancing port reuse, so that a listener per lane
--- shares one port. Refused where the platform's semantics are not load
--- balancing rather than quietly degraded, so a program depending on it
--- learns at bind.
reusePort: boolean?
}
```
How a listener is opened.
### `Message` _record_
```nupp
record net.Message
length: integer
address: net.Address
truncated: boolean
end
```
What one received datagram was.
The bytes are not here: they went into the storage the receive named. What
is here is everything a caller cannot get from those bytes -- how many of
them landed, who sent them, and whether the rest is gone.
#### Fields
##### `length`
```nupp
length: integer
```
How many bytes landed in the storage offered.
##### `address`
```nupp
address: net.Address
```
The peer that sent them.
##### `truncated`
```nupp
truncated: boolean
```
Whether the datagram was larger than the storage offered, so that what
landed is the beginning of a message rather than a message.
Never silently false: a protocol that parses the first 1500 bytes of a
larger datagram without being told is parsing something nobody sent, and
that is a security bug rather than a lost packet.
### `Stream` _record_
```nupp
record net.Stream is Reader, Writer
function isReleased(self): boolean end
function isEnded(self): boolean end
function pending(self): integer end
function peerAddress(self): net.Address? end
function localAddress(self): net.Address? end
function setNoDelay(self, enable: boolean): (boolean, string?) end
function setKeepAlive(self, enable: boolean, delaySeconds: integer): (boolean, string?) end
function read(self, count: integer): (string?, string?) end
function readSpan(self, exclusive destination: span.Writable): (integer?, string?) end
function readInto(self, exclusive destination: Buffer, offset: integer?, count: integer?): (integer?, string?) end
function transferTo(self, exclusive destination: Writer): (integer?, string?) end
function write(exclusive self, bytes: string): (boolean, string?) end
function writeSpan(exclusive self, borrows source: span.ByteSpan): (integer?, string?) end
function flush(self): (boolean, string?) end
function shutdownWrite(self): (boolean, string?) end
function close(takes self): nil end
end
```
One connection.
The owner of the socket, and the only cleanup obligation: a direction view
borrows this and ends a direction, while `close` here ends the connection.
#### Methods
##### `isReleased`
```nupp
isReleased: function isReleased(self): boolean
```
Whether this side has released the connection.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
##### `isEnded`
```nupp
isEnded: function isEnded(self): boolean
```
Whether the peer closed its sending half and nothing is left buffered.
A read answers empty exactly when this is true, which is what keeps a
quiet connection and a finished one apart.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
##### `pending`
```nupp
pending: function pending(self): integer
```
How many bytes this process still holds unsent.
A local fact and not a delivery receipt: bytes leave this count when the
platform takes them, which says nothing about the peer having read them.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
##### `peerAddress`
```nupp
peerAddress: function peerAddress(self): net.Address?
```
Who is at the other end, or nil for a connection that has no peer
address.
A Unix socket has a filesystem name and no peer address, and answers nil
rather than something that looks like one.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `net.Address?` | |
##### `localAddress`
```nupp
localAddress: function localAddress(self): net.Address?
```
Which of this machine's addresses the connection is on, or nil where
there is none.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `net.Address?` | |
##### `setNoDelay`
```nupp
setNoDelay: function setNoDelay(self, enable: boolean): boolean, string?
```
Turns Nagle's algorithm off, so a small write goes out now.
The kernel coalesces small writes by default, which can hold a reply for
tens of milliseconds waiting for more to send. That is the right trade
for bulk transfer and the wrong one for a protocol that answers
requests, so a server usually wants this on every connection it accepts.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this connection |
| `enable` | `boolean` | whether to send small writes immediately |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether the option was set |
| `string?` | why it was not, when unsuccessful |
##### `setKeepAlive`
```nupp
setKeepAlive: function setKeepAlive(self, enable: boolean, delaySeconds: integer): boolean, string?
```
Asks the kernel to probe an idle connection.
A peer that vanished without closing leaves a connection that looks open
forever. Probing is what eventually notices, and the delay is how long
the connection may be idle before the first probe.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this connection |
| `enable` | `boolean` | whether to probe |
| `delaySeconds` | `integer` | idle seconds before the first probe |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether the option was set |
| `string?` | why it was not, when unsuccessful |
###### Raises
- when the delay is not a positive integer
##### `read`
```nupp
read: function read(self, count: integer): string?, string?
```
Reads up to `count` bytes, suspending while none have arrived.
An empty answer is the end, as the contract says, and it is only ever the
end: a quiet connection parks rather than answering zero.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this connection |
| `count` | `integer` | the most bytes to read |
###### Returns
| Type | Description |
| --- | --- |
| `string?` | the bytes, or nil when the connection is closed |
| `string?` | why it could not read, when unsuccessful |
###### Raises
- when count is not a positive integer
##### `readSpan`
```nupp
readSpan: function readSpan(self, exclusive destination: span.Writable): integer?, string?
```
Reads directly into a checked writable span. A zero answer is the end.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this connection |
| `exclusive destination` | `span.Writable\` | the positive-sized range to fill |
###### Returns
| Type | Description |
| --- | --- |
| `integer?` | how many bytes were read, or nil when the connection is closed |
| `string?` | why it could not read, when unsuccessful |
###### Raises
- when the destination is empty
##### `readInto`
```nupp
readInto: function readInto(self, exclusive destination: Buffer, offset: integer?, count: integer?): integer?, string?
```
Reads into a buffer. A zero answer is the end.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this connection |
| `exclusive destination` | `Buffer` | the buffer to write into |
| `offset` | `integer?` | where in the destination to start, or the beginning |
| `count` | `integer?` | the most bytes to read |
###### Returns
| Type | Description |
| --- | --- |
| `integer?` | how many bytes were read, or nil when the connection is closed |
| `string?` | why it could not read, when unsuccessful |
###### Raises
- when count is not a positive integer
##### `transferTo`
```nupp
transferTo: function transferTo(self, exclusive destination: Writer): integer?, string?
```
Writes everything left to a writer.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this connection |
| `exclusive destination` | `Writer` | the writer to fill |
###### Returns
| Type | Description |
| --- | --- |
| `integer?` | how many bytes moved, or nil on failure |
| `string?` | why it could not, when unsuccessful |
##### `write`
```nupp
write: function write(exclusive self, bytes: string): boolean, string?
```
Appends bytes, waiting where the send queue is already at its maximum.
The whole value is written, as the contract promises. An input larger than
`sendHighWater` is submitted in pieces that fit beneath it, so the bound
governs how much is queued at one time rather than how much may be sent.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `exclusive self` | `any` | this connection |
| `bytes` | `string` | the bytes to append |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether they were written |
| `string?` | why they were not, when unsuccessful |
##### `writeSpan`
```nupp
writeSpan: function writeSpan(exclusive self, borrows source: span.ByteSpan): integer?, string?
```
Appends bytes from a checked shared span.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `exclusive self` | `any` | this connection |
| `borrows source` | `span.ByteSpan` | bytes valid for the duration of the call |
###### Returns
| Type | Description |
| --- | --- |
| `integer?` | how many bytes moved, or nil on failure |
| `string?` | why it could not, when unsuccessful |
##### `flush`
```nupp
flush: function flush(self): boolean, string?
```
Waits until nothing this connection accepted is still held here.
Unlike a buffer's writer there is something to flush: `write` completes
when the platform takes the bytes, and the platform may still be holding
them. A caller that writes, flushes and closes would otherwise lose
whatever was queued, because closing cancels queued writes.
Still not a delivery receipt. It says the bytes left this process, not
that anybody read them.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this connection |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether everything left |
| `string?` | why it did not, when unsuccessful |
##### `shutdownWrite`
```nupp
shutdownWrite: function shutdownWrite(self): boolean, string?
```
Ends the sending half and leaves the receiving half open, so the peer sees
end of stream while this side goes on reading.
This is what a graceful drain is built from. `close` ends the connection
in both directions and cannot wait for a peer, so a handler with a
response still to deliver finishes it, half-closes, and then releases.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `any` | this connection |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | whether the sending half was ended |
| `string?` | why it was not, when unsuccessful |
##### `close`
```nupp
close: function close(takes self): nil
```
Releases the connection in both directions.
Idempotent, and terminal: this is the cleanup obligation the owner carries.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `takes self` | `any` | |
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
## Functions
### `net.asReader` _function_
```nupp
function net.asReader(borrows source: net.Stream): affine(net.DirectionView)
```
Borrows a connection's reading half through the shared contract.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `borrows source` | `net.Stream` | the connection to view |
#### Returns
| Type | Description |
| --- | --- |
| `affine(net.DirectionView)` | the view, which may not outlive it |
### `net.asWriter` _function_
```nupp
function net.asWriter(borrows source: net.Stream): affine(net.DirectionView)
```
Borrows a connection's writing half through the shared contract.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `borrows source` | `net.Stream` | the connection to view |
#### Returns
| Type | Description |
| --- | --- |
| `affine(net.DirectionView)` | the view, which may not outlive it |
### `net.bind` _function_
```nupp
function net.bind(options: net.DatagramOptions): affine(net.Datagram)?, string?
```
Opens a datagram socket.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `options` | `net.DatagramOptions` | where to bind |
#### Returns
| Type | Description |
| --- | --- |
| `affine(net.Datagram)?` | the socket, which the caller owns and must close |
| `string?` | why it could not bind, when unsuccessful |
#### Raises
- when the options do not describe a bindable address
### `net.connect` _function_
```nupp
function net.connect(options: net.ConnectOptions): affine(net.Stream)?, string?
```
Opens a connection, resolving the peer's name off this frame.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `options` | `net.ConnectOptions` | who to reach and how much may be queued unsent |
#### Returns
| Type | Description |
| --- | --- |
| `affine(net.Stream)?` | the connection, which the caller owns and must close |
| `string?` | why it could not connect, when unsuccessful |
#### Raises
- when the options do not describe a reachable peer
### `net.listen` _function_
```nupp
function net.listen(options: net.ListenOptions): affine(net.Listener)?, string?
```
Opens a listener.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `options` | `net.ListenOptions` | where to bind and how deep a backlog to ask for |
#### Returns
| Type | Description |
| --- | --- |
| `affine(net.Listener)?` | the listener, which the caller owns and must close |
| `string?` | why it could not bind, when unsuccessful |
#### Raises
- when the options do not describe a bindable address
### `net.pump` _function_
```nupp
function net.pump(timeoutMs: integer): nil
```
Advances the selected network reactor.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `timeoutMs` | `integer` | |
#### Returns
| Type | Description |
| --- | --- |
| `nil` | |