# net

Dark Mode

- Manual
- Standard library
- Index

Search:
Group by:

This module implements a high-level cross-platform sockets interface. The procedures implemented in this module are primarily for blocking sockets. For asynchronous non-blocking sockets use the `asyncnet` module together with the `asyncdispatch` module.

The first thing you will always need to do in order to start using sockets, is to create a new instance of the `Socket` type using the `newSocket` procedure.

# SSL

In order to use the SSL procedures defined in this module, you will need to compile your application with the `-d:ssl` flag.

# Examples

## Connecting to a server

After you create a socket with the `newSocket` procedure, you can easily connect it to a server running at a known hostname (or IP address) and port. To do so over TCP, use the example below.

    var socket = newSocket()
    socket.connect("google.com", Port(80))

UDP is a connectionless protocol, so UDP sockets don't have to explicitly call the `connect` procedure. They can simply start sending data immediately.

    var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
    socket.sendTo("192.168.0.1", Port(27960), "status\n")

## Creating a server

After you create a socket with the `newSocket` procedure, you can create a TCP server by calling the `bindAddr` and `listen` procedures.

    var socket = newSocket()
    socket.bindAddr(Port(1234))
    socket.listen()

You can then begin accepting connections using the `accept` procedure.

    var client: Socket
    var address = ""
    while true:
      socket.acceptAddr(client, address)
      echo("Client connected from: ", address)

# Imports

nativesockets, os, strutils, times, sets, options, monotimes, ssl_certs, openssl, winlean

# Types

    Certificate = string

  DER encoded certificate Source Edit

    SslError = object of Exception

  Source Edit

    SslCVerifyMode = enum
      CVerifyNone, CVerifyPeer, CVerifyPeerUseEnvVars

  Source Edit

    SslProtVersion = enum
      protSSLv2, protSSLv3, protTLSv1, protSSLv23

  Source Edit

    SslContext = ref object
      context*: SslCtx
      referencedData: HashSet[int]
      extraInternal: SslContextExtraInternal

  Source Edit

    SslAcceptResult = enum
      AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess

  Source Edit

    SslHandshakeType = enum
      handshakeAsClient, handshakeAsServer

  Source Edit

    SslClientGetPskFunc = proc (hint: string): tuple[identity: string, psk: string]

  Source Edit

    SslServerGetPskFunc = proc (identity: string): string

  Source Edit

    SocketImpl = object
      fd: SocketHandle
      isBuffered: bool
      buffer: array[0 .. BufferSize, char]
      currPos: int
      bufLen: int
      when defineSsl:
          isSsl: bool
          sslHandle: SslPtr
          sslContext: SslContext
          sslNoHandshake: bool
          sslHasPeekChar: bool
          sslPeekChar: char

      lastError: OSErrorCode     ## stores the last error on this socket
      domain: Domain
      sockType: SockType
      protocol: Protocol

  socket type Source Edit

    Socket = ref SocketImpl

  Source Edit

    SOBool = enum
      OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
      OptOOBInline, OptReuseAddr, OptReusePort, OptNoDelay

  Boolean socket options. Source Edit

    ReadLineResult = enum
      ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone

  result for readLineAsync Source Edit

    TimeoutError = object of Exception

  Source Edit

    SocketFlag {...}{.pure.} = enum
      Peek, SafeDisconn          ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown.

  Source Edit

    IpAddressFamily {...}{.pure.} = enum
      IPv6,                     ## IPv6 address
      IPv4                       ## IPv4 address

  Describes the type of an IP address Source Edit

    IpAddress = object
      case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
      of IpAddressFamily.IPv6:
          address_v6*: array[0 .. 15, uint8] ## Contains the IP address in bytes in
                                             ## case of IPv6

      of IpAddressFamily.IPv4:
          address_v4*: array[0 .. 3, uint8] ## Contains the IP address in bytes in
                                            ## case of IPv4

  stores an arbitrary IP address Source Edit

# Consts

    BufferSize: int = 4000

  size of a buffered socket's buffer Source Edit

    MaxLineLength = 1000000

  Source Edit

# Procs

    proc isDisconnectionError(flags: set[SocketFlag]; lastError: OSErrorCode): bool {...}{.
        raises: [], tags: [].}

  Determines whether `lastError` is a disconnection error. Only does this if flags contains `SafeDisconn`. Source Edit

    proc toOSFlags(socketFlags: set[SocketFlag]): cint {...}{.raises: [], tags: [].}

  Converts the flags into the underlying OS representation. Source Edit

    proc newSocket(fd: SocketHandle; domain: Domain = AF_INET;
                   sockType: SockType = SOCK_STREAM;
                   protocol: Protocol = IPPROTO_TCP; buffered = true): owned(Socket) {...}{.
        raises: [], tags: [].}

  Creates a new socket as specified by the params. Source Edit

    proc newSocket(domain, sockType, protocol: cint; buffered = true): owned(Socket) {...}{.
        raises: [OSError], tags: [].}

  Creates a new socket.

  If an error occurs OSError will be raised.

  Source Edit

    proc newSocket(domain: Domain = AF_INET; sockType: SockType = SOCK_STREAM;
                   protocol: Protocol = IPPROTO_TCP; buffered = true): owned(Socket) {...}{.
        raises: [OSError], tags: [].}

  Creates a new socket.

  If an error occurs OSError will be raised.

  Source Edit

    proc parseIpAddress(addressStr: string): IpAddress {...}{.raises: [ValueError],
        tags: [].}

  Parses an IP address Raises ValueError on error Source Edit

    proc isIpAddress(addressStr: string): bool {...}{.tags: [], raises: [].}

  Checks if a string is an IP address Returns true if it is, false otherwise Source Edit

    proc toSockAddr(address: IpAddress; port: Port; sa: var Sockaddr_storage;
                    sl: var SockLen) {...}{.raises: [], tags: [].}

  Converts `IpAddress` and `Port` to `SockAddr` and `SockLen` Source Edit

    proc fromSockAddr(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6;
                      sl: SockLen; address: var IpAddress; port: var Port) {...}{.inline.}

  Converts `SockAddr` and `SockLen` to `IpAddress` and `Port`. Raises `ObjectConversionError` in case of invalid `sa` and `sl` arguments. Source Edit

    proc raiseSSLError(s = "") {...}{.raises: [SslError, OSError], tags: [].}

  Raises a new SSL error. Source Edit

    proc getExtraData(ctx: SslContext; index: int): RootRef {...}{.
        raises: [IndexError, SslError, OSError], tags: [].}

  Retrieves arbitrary data stored inside SslContext. Source Edit

    proc setExtraData(ctx: SslContext; index: int; data: RootRef) {...}{.
        raises: [IndexError, SslError, OSError], tags: [].}

  Stores arbitrary data inside SslContext. The unique `index` should be retrieved using getSslContextExtraDataIndex. Source Edit

    proc newContext(protVersion = protSSLv23; verifyMode = CVerifyPeer;
                    certFile = ""; keyFile = ""; cipherList = "ALL"; caDir = "";
                    caFile = ""): SslContext {...}{.
        raises: [Exception, LibraryError, SslError, OSError, IOError],
        tags: [RootEffect, ReadDirEffect].}

  Creates an SSL context.

  Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are available with the addition of `protSSLv23` which allows for compatibility with all of them.

  There are three options for verify mode: `CVerifyNone`: certificates are not verified; `CVerifyPeer`: certificates are verified; `CVerifyPeerUseEnvVars`: certificates are verified and the optional environment variables SSL_CERT_FILE and SSL_CERT_DIR are also used to locate certificates

  The `nimDisableCertificateValidation` define overrides verifyMode and disables certificate verification globally!

  CA certificates will be loaded, in the following order, from:

  > - caFile, caDir, parameters, if set
  > - if `verifyMode` is set to `CVerifyPeerUseEnvVars`, the SSL_CERT_FILE and SSL_CERT_DIR environment variables are used
  > - a set of files and directories from the ssl_certs file.

  The last two parameters specify the certificate file path and the key file path, a server socket will most likely not work without these.

  Certificates can be generated using the following command:

  - `openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout mykey.pem -out mycert.pem`

  or using ECDSA:

  - `openssl ecparam -out mykey.pem -name secp256k1 -genkey`
  - `openssl req -new -key mykey.pem -x509 -nodes -days 365 -out mycert.pem`
  Source Edit

    proc destroyContext(ctx: SslContext) {...}{.raises: [IndexError, SslError, OSError],
                                           tags: [].}

  Free memory referenced by SslContext. Source Edit

    proc pskIdentityHint=(ctx: SslContext; hint: string) {...}{.
        raises: [SslError, OSError], tags: [].}

  Sets the identity hint passed to server.

  Only used in PSK ciphersuites.

  Source Edit

    proc clientGetPskFunc(ctx: SslContext): SslClientGetPskFunc {...}{.raises: [],
        tags: [].}

  Source Edit

    proc clientGetPskFunc=(ctx: SslContext; fun: SslClientGetPskFunc) {...}{.
        raises: [Exception], tags: [RootEffect].}

  Sets function that returns the client identity and the PSK based on identity hint from the server.

  Only used in PSK ciphersuites.

  Source Edit

    proc serverGetPskFunc(ctx: SslContext): SslServerGetPskFunc {...}{.raises: [],
        tags: [].}

  Source Edit

    proc serverGetPskFunc=(ctx: SslContext; fun: SslServerGetPskFunc) {...}{.
        raises: [Exception], tags: [RootEffect].}

  Sets function that returns PSK based on the client identity.

  Only used in PSK ciphersuites.

  Source Edit

    proc getPskIdentity(socket: Socket): string {...}{.raises: [], tags: [].}

  Gets the PSK identity provided by the client. Source Edit

    proc wrapSocket(ctx: SslContext; socket: Socket) {...}{.raises: [SslError, OSError],
        tags: [].}

  Wraps a socket in an SSL context. This function effectively turns `socket` into an SSL socket.

  This must be called on an unconnected socket; an SSL session will be started when the socket is connected.

  FIXME: Disclaimer: This code is not well tested, may be very unsafe and prone to security vulnerabilities.

  Source Edit

    proc wrapConnectedSocket(ctx: SslContext; socket: Socket;
                             handshake: SslHandshakeType; hostname: string = "") {...}{.
        raises: [SslError, OSError, Exception], tags: [RootEffect].}

  Wraps a connected socket in an SSL context. This function effectively turns `socket` into an SSL socket. `hostname` should be specified so that the client knows which hostname the server certificate should be validated against.

  This should be called on a connected socket, and will perform an SSL handshake immediately.

  FIXME: Disclaimer: This code is not well tested, may be very unsafe and prone to security vulnerabilities.

  Source Edit

    proc getPeerCertificates(sslHandle: SslPtr): seq[Certificate] {...}{.
        raises: [Exception], tags: [].}

  Returns the certificate chain received by the peer we are connected to through the OpenSSL connection represented by `sslHandle`. The handshake must have been completed and the certificate chain must have been verified successfully or else an empty sequence is returned. The chain is ordered from leaf certificate to root certificate. Source Edit

    proc getPeerCertificates(socket: Socket): seq[Certificate] {...}{.
        raises: [Exception], tags: [].}

  Returns the certificate chain received by the peer we are connected to through the given socket. The handshake must have been completed and the certificate chain must have been verified successfully or else an empty sequence is returned. The chain is ordered from leaf certificate to root certificate. Source Edit

    proc getSocketError(socket: Socket): OSErrorCode {...}{.raises: [OSError], tags: [].}

  Checks `osLastError` for a valid error. If it has been reset it uses the last error stored in the socket object. Source Edit

    proc socketError(socket: Socket; err: int = -1; async = false;
                     lastError = -1.OSErrorCode): void {...}{.gcsafe,
        raises: [SslError, OSError], tags: [].}

  Raises an OSError based on the error code returned by `SSL_get_error` (for SSL sockets) and `osLastError` otherwise.

  If `async` is `true` no error will be thrown in the case when the error was caused by no data being available to be read.

  If `err` is not lower than 0 no exception will be raised.

  Source Edit

    proc listen(socket: Socket; backlog = SOMAXCONN) {...}{.tags: [ReadIOEffect],
        raises: [OSError].}

  Marks `socket` as accepting connections. `Backlog` specifies the maximum length of the queue of pending connections.

  Raises an OSError error upon failure.

  Source Edit

    proc bindAddr(socket: Socket; port = Port(0); address = "") {...}{.
        tags: [ReadIOEffect], raises: [ValueError, OSError].}

  Binds `address`:`port` to the socket.

  If `address` is "" then ADDR_ANY will be bound.

  Source Edit

    proc acceptAddr(server: Socket; client: var owned(Socket); address: var string;
                    flags = {SafeDisconn}) {...}{.tags: [ReadIOEffect], gcsafe, locks: 0,
        raises: [OSError, IOError, SslError].}

  Blocks until a connection is being made from a client. When a connection is made sets `client` to the client socket and `address` to the address of the connecting client. This function will raise OSError if an error occurs.

  The resulting client will inherit any properties of the server socket. For example: whether the socket is buffered or not.

  The `accept` call may result in an error if the connecting socket disconnects during the duration of the `accept`. If the `SafeDisconn` flag is specified then this error will not be raised and instead accept will be called again.

  Source Edit

    proc accept(server: Socket; client: var owned(Socket); flags = {SafeDisconn}) {...}{.
        tags: [ReadIOEffect], raises: [OSError, IOError, SslError].}

  Equivalent to `acceptAddr` but doesn't return the address, only the socket.

  The `accept` call may result in an error if the connecting socket disconnects during the duration of the `accept`. If the `SafeDisconn` flag is specified then this error will not be raised and instead accept will be called again.

  Source Edit

    proc close(socket: Socket) {...}{.raises: [SslError, OSError], tags: [].}

  Closes a socket. Source Edit

    proc toCInt(opt: SOBool): cint {...}{.raises: [], tags: [].}

  Converts a `SOBool` into its Socket Option cint representation. Source Edit

    proc getSockOpt(socket: Socket; opt: SOBool; level = SOL_SOCKET): bool {...}{.
        tags: [ReadIOEffect], raises: [OSError].}

  Retrieves option `opt` as a boolean value. Source Edit

    proc getLocalAddr(socket: Socket): (string, Port) {...}{.
        raises: [OSError, Exception], tags: [].}

  Get the socket's local address and port number.

  This is high-level interface for getsockname.

  Source Edit

    proc getPeerAddr(socket: Socket): (string, Port) {...}{.raises: [OSError, Exception],
        tags: [].}

  Get the socket's peer address and port number.

  This is high-level interface for getpeername.

  Source Edit

    proc setSockOpt(socket: Socket; opt: SOBool; value: bool; level = SOL_SOCKET) {...}{.
        tags: [WriteIOEffect], raises: [OSError].}

  Sets option `opt` to a boolean value specified by `value`.

      var socket = newSocket()
      socket.setSockOpt(OptReusePort, true)
      socket.setSockOpt(OptNoDelay, true, level=IPPROTO_TCP.toInt)

  Source Edit

    proc connectUnix(socket: Socket; path: string) {...}{.raises: [], tags: [].}

  Connects to Unix socket on `path`. This only works on Unix-style systems: Mac OS X, BSD and Linux Source Edit

    proc bindUnix(socket: Socket; path: string) {...}{.raises: [], tags: [].}

  Binds Unix socket to `path`. This only works on Unix-style systems: Mac OS X, BSD and Linux Source Edit

    proc hasDataBuffered(s: Socket): bool {...}{.raises: [], tags: [].}

  Determines whether a socket has data buffered. Source Edit

    proc recv(socket: Socket; data: pointer; size: int): int {...}{.tags: [ReadIOEffect],
        raises: [].}

  Receives data from a socket.

  Note: This is a low-level function, you may be interested in the higher level versions of this function which are also named `recv`.

  Source Edit

    proc recv(socket: Socket; data: pointer; size: int; timeout: int): int {...}{.
        tags: [ReadIOEffect, TimeEffect], raises: [TimeoutError, OSError].}

  overload with a `timeout` parameter in milliseconds. Source Edit

    proc recv(socket: Socket; data: var string; size: int; timeout = -1;
              flags = {SafeDisconn}): int {...}{.raises: [TimeoutError, OSError, SslError],
                                            tags: [ReadIOEffect, TimeEffect].}

  Higher-level version of `recv`.

  Reads up to `size` bytes from `socket` into `buf`.

  For buffered sockets this function will attempt to read all the requested data. It will read this data in `BufferSize` chunks.

  For unbuffered sockets this function makes no effort to read all the data requested. It will return as much data as the operating system gives it.

  When 0 is returned the socket's connection has been closed.

  This function will throw an OSError exception when an error occurs. A value lower than 0 is never returned.

  A timeout may be specified in milliseconds, if enough data is not received within the time specified a TimeoutError exception will be raised.

  Note: `data` must be initialised.

  Warning: Only the `SafeDisconn` flag is currently supported.

  Source Edit

    proc recv(socket: Socket; size: int; timeout = -1; flags = {SafeDisconn}): string {...}{.
        inline, raises: [TimeoutError, OSError, SslError],
        tags: [ReadIOEffect, TimeEffect].}

  Higher-level version of `recv` which returns a string.

  Reads up to `size` bytes from `socket` into `buf`.

  For buffered sockets this function will attempt to read all the requested data. It will read this data in `BufferSize` chunks.

  For unbuffered sockets this function makes no effort to read all the data requested. It will return as much data as the operating system gives it.

  When `""` is returned the socket's connection has been closed.

  This function will throw an OSError exception when an error occurs.

  A timeout may be specified in milliseconds, if enough data is not received within the time specified a TimeoutError exception will be raised.

  Warning: Only the `SafeDisconn` flag is currently supported.

  Source Edit

    proc readLine(socket: Socket; line: var TaintedString; timeout = -1;
                  flags = {SafeDisconn}; maxLength = MaxLineLength) {...}{.
        tags: [ReadIOEffect, TimeEffect], raises: [TimeoutError, OSError, SslError].}

  Reads a line of data from `socket`.

  If a full line is read `\r\L` is not added to `line`, however if solely `\r\L` is read then `line` will be set to it.

  If the socket is disconnected, `line` will be set to `""`.

  An OSError exception will be raised in the case of a socket error.

  A timeout can be specified in milliseconds, if data is not received within the specified time a TimeoutError exception will be raised.

  The `maxLength` parameter determines the maximum amount of characters that can be read. The result is truncated after that.

  Warning: Only the `SafeDisconn` flag is currently supported.

  Source Edit

    proc recvLine(socket: Socket; timeout = -1; flags = {SafeDisconn};
                  maxLength = MaxLineLength): TaintedString {...}{.
        raises: [TimeoutError, OSError, SslError], tags: [ReadIOEffect, TimeEffect].}

  Reads a line of data from `socket`.

  If a full line is read `\r\L` is not added to the result, however if solely `\r\L` is read then the result will be set to it.

  If the socket is disconnected, the result will be set to `""`.

  An OSError exception will be raised in the case of a socket error.

  A timeout can be specified in milliseconds, if data is not received within the specified time a TimeoutError exception will be raised.

  The `maxLength` parameter determines the maximum amount of characters that can be read. The result is truncated after that.

  Warning: Only the `SafeDisconn` flag is currently supported.

  Source Edit

    proc recvFrom(socket: Socket; data: var string; length: int;
                  address: var string; port: var Port; flags = 0'i32): int {...}{.
        tags: [ReadIOEffect], raises: [Exception, OSError, IOError].}

  Receives data from `socket`. This function should normally be used with connection-less sockets (UDP sockets).

  If an error occurs an OSError exception will be raised. Otherwise the return value will be the length of data received.

  Warning: This function does not yet have a buffered implementation, so when `socket` is buffered the non-buffered implementation will be used. Therefore if `socket` contains something in its buffer this function will make no effort to return it.

  Source Edit

    proc skip(socket: Socket; size: int; timeout = -1) {...}{.
        raises: [TimeoutError, OSError], tags: [TimeEffect, ReadIOEffect].}

  Skips `size` amount of bytes.

  An optional timeout can be specified in milliseconds, if skipping the bytes takes longer than specified a TimeoutError exception will be raised.

  Returns the number of skipped bytes.

  Source Edit

    proc send(socket: Socket; data: pointer; size: int): int {...}{.
        tags: [WriteIOEffect], raises: [].}

  Sends data to a socket.

  Note: This is a low-level version of `send`. You likely should use the version below.

  Source Edit

    proc send(socket: Socket; data: string; flags = {SafeDisconn}) {...}{.
        tags: [WriteIOEffect], raises: [SslError, OSError].}

  sends data to a socket. Source Edit

    proc trySend(socket: Socket; data: string): bool {...}{.tags: [WriteIOEffect],
        raises: [].}

  Safe alternative to `send`. Does not raise an OSError when an error occurs, and instead returns `false` on failure. Source Edit

    proc sendTo(socket: Socket; address: string; port: Port; data: pointer;
                size: int; af: Domain = AF_INET; flags = 0'i32) {...}{.
        tags: [WriteIOEffect], raises: [OSError].}

  This proc sends `data` to the specified `address`, which may be an IP address or a hostname, if a hostname is specified this function will try each IP of that hostname.

  If an error occurs an OSError exception will be raised.

  Note: You may wish to use the high-level version of this function which is defined below.

  Note: This proc is not available for SSL sockets.

  Source Edit

    proc sendTo(socket: Socket; address: string; port: Port; data: string) {...}{.
        tags: [WriteIOEffect], raises: [OSError].}

  This proc sends `data` to the specified `address`, which may be an IP address or a hostname, if a hostname is specified this function will try each IP of that hostname.

  If an error occurs an OSError exception will be raised.

  This is the high-level version of the above `sendTo` function.

  Source Edit

    proc isSsl(socket: Socket): bool {...}{.raises: [], tags: [].}

  Determines whether `socket` is a SSL socket. Source Edit

    proc getFd(socket: Socket): SocketHandle {...}{.raises: [], tags: [].}

  Returns the socket's file descriptor Source Edit

    proc IPv4_any(): IpAddress {...}{.raises: [], tags: [].}

  Returns the IPv4 any address, which can be used to listen on all available network adapters Source Edit

    proc IPv4_loopback(): IpAddress {...}{.raises: [], tags: [].}

  Returns the IPv4 loopback address (127.0.0.1) Source Edit

    proc IPv4_broadcast(): IpAddress {...}{.raises: [], tags: [].}

  Returns the IPv4 broadcast address (255.255.255.255) Source Edit

    proc IPv6_any(): IpAddress {...}{.raises: [], tags: [].}

  Returns the IPv6 any address (::0), which can be used to listen on all available network adapters Source Edit

    proc IPv6_loopback(): IpAddress {...}{.raises: [], tags: [].}

  Returns the IPv6 loopback address (::1) Source Edit

    proc `==`(lhs, rhs: IpAddress): bool {...}{.raises: [], tags: [].}

  Compares two IpAddresses for Equality. Returns true if the addresses are equal Source Edit

    proc `$`(address: IpAddress): string {...}{.raises: [], tags: [].}

  Converts an IpAddress into the textual representation Source Edit

    proc dial(address: string; port: Port; protocol = IPPROTO_TCP; buffered = true): owned(
        Socket) {...}{.tags: [ReadIOEffect, WriteIOEffect], raises: [OSError, IOError].}

  Establishes connection to the specified `address`:`port` pair via the specified protocol. The procedure iterates through possible resolutions of the `address` until it succeeds, meaning that it seamlessly works with both IPv4 and IPv6. Returns Socket ready to send or receive data. Source Edit

    proc connect(socket: Socket; address: string; port = Port(0)) {...}{.
        tags: [ReadIOEffect], raises: [OSError, SslError].}

  Connects socket to `address`:`port`. `Address` can be an IP address or a host name. If `address` is a host name, this function will try each IP of that host name. `htons` is already performed on `port` so you must not do it.

  If `socket` is an SSL socket a handshake will be automatically performed.

  Source Edit

    proc connect(socket: Socket; address: string; port = Port(0); timeout: int) {...}{.
        tags: [ReadIOEffect, WriteIOEffect], raises: [OSError, TimeoutError].}

  Connects to server as specified by `address` on port specified by `port`.

  The `timeout` parameter specifies the time in milliseconds to allow for the connection to the server to be made.

  Source Edit

    proc getPrimaryIPAddr(dest = parseIpAddress("8.8.8.8")): IpAddress {...}{.
        raises: [OSError, SslError, ValueError, Exception], tags: [ReadIOEffect].}

  Finds the local IP address, usually assigned to eth0 on LAN or wlan0 on WiFi, used to reach an external address. Useful to run local services.

  No traffic is sent.

  Supports IPv4 and v6. Raises OSError if external networking is not set up.

      echo $getPrimaryIPAddr()  # "192.168.1.2"

  Source Edit

# Templates

    template `&=`(socket: Socket; data: typed)

  an alias for 'send'. Source Edit

# Exports

Port, $, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, ==, Domain, SockType, Protocol