# Module sockets

This module implements portable sockets, it supports a mix of different types of sockets. Sockets are buffered by default meaning that data will be received in `BufferSize` (4000) sized chunks, buffering behaviour can be disabled by setting the `buffered` parameter when calling the `socket` function to False. Be aware that some functions may not yet support buffered sockets (mainly the recvFrom function).

Most procedures raise EOS on error, but some may return `-1` or a boolean `False`.

SSL is supported through the OpenSSL library. This support can be activated by compiling with the `-d:ssl` switch. When an SSL socket is used it will raise ESSL exceptions when SSL errors occur.

Asynchronous sockets are supported, however a better alternative is to use the asyncio module.

# Imports

os, parseutils, times, posix

# Types

    TSocket = ref TSocketImpl

    TPort = distinct int16

  port type

    TDomain = enum
      AF_UNIX,                    ## for local socket (using a file). Unsupported on Windows.
      AF_INET = 2,                ## for network protocol IPv4 or
      AF_INET6 = 23               ## for network protocol IPv6.

  domain, which specifies the protocol family of the created socket. Other domains than those that are listed here are unsupported.

    TType = enum
      SOCK_STREAM = 1,            ## reliable stream-oriented service or Stream Sockets
      SOCK_DGRAM = 2,             ## datagram service or Datagram Sockets
      SOCK_RAW = 3,               ## raw protocols atop the network layer.
      SOCK_SEQPACKET = 5          ## reliable sequenced packet service

  second argument to socket proc

    TProtocol = enum
      IPPROTO_TCP = 6,            ## Transmission control protocol.
      IPPROTO_UDP = 17,           ## User datagram protocol.
      IPPROTO_IP,                 ## Internet protocol. Unsupported on Windows.
      IPPROTO_IPV6,               ## Internet Protocol Version 6. Unsupported on Windows.
      IPPROTO_RAW,                ## Raw IP Packets Protocol. Unsupported on Windows.
      IPPROTO_ICMP                ## Control message protocol. Unsupported on Windows.

  third argument to socket proc

    TServent = object
      name*: string
      aliases*: seq[string]
      port*: TPort
      proto*: string

  information about a service

    Thostent = object
      name*: string
      aliases*: seq[string]
      addrtype*: TDomain
      length*: int
      addrList*: seq[string]

  information about a given host

    TRecvLineResult = enum
      RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail

  result for recvLineAsync

    TReadLineResult = enum
      ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone

  result for readLineAsync

    ETimeout = object of ESynch

# Lets

    InvalidSocket: TSocket = nil

  invalid socket

# Consts

    BufferSize = 4000

  size of a buffered socket's buffer

# Procs

    proc `==`(a, b: TPort): bool {.borrow.}

  `==` for ports.

    proc `$`(p: TPort): string {.raises: [], tags: [].}

  returns the port number as a string

    proc ntohl(x: int32): int32 {.raises: [], tags: [].}

  Converts 32-bit integers from network to host byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 4-byte swap operation.

    proc ntohs(x: int16): int16 {.raises: [], tags: [].}

  Converts 16-bit integers from network to host byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 2-byte swap operation.

    proc htonl(x: int32): int32 {.raises: [], tags: [].}

  Converts 32-bit integers from host to network byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 4-byte swap operation.

    proc htons(x: int16): int16 {.raises: [], tags: [].}

  Converts 16-bit positive integers from host to network byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 2-byte swap operation.

    proc socket(domain: TDomain = AF_INET; typ: TType = SOCK_STREAM;
                protocol: TProtocol = IPPROTO_TCP; buffered = true): TSocket {.
        raises: [], tags: [].}

  Creates a new socket; returns InvalidSocket if an error occurs.

    proc SocketError(socket: TSocket; err: int = - 1; async = false) {.
        raises: [EOS], tags: [].}

  Raises proper errors based on return values of `recv` functions.

  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.

    proc listen(socket: TSocket; backlog = SOMAXCONN) {.tags: [FReadIO],
        raises: [EOS].}

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

    proc parseIp4(s: string): int32 {.raises: [EOverflow, EInvalidValue], tags: [].}

  parses an IP version 4 in dotted decimal form like "a.b.c.d". Raises EInvalidValue in case of an error.

    proc bindAddr(socket: TSocket; port = TPort(0); address = "") {.tags: [FReadIO],
        raises: [EOS].}

  binds an address/port number to a socket. Use address string in dotted decimal form like "a.b.c.d" or leave "" for any address.

    proc getSockName(socket: TSocket): TPort {.raises: [EOS], tags: [].}

  returns the socket's associated port number.

    proc acceptAddr(server: TSocket; client: var TSocket; address: var string) {.
        tags: [FReadIO], raises: [EOS].}

  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. If `server` is non-blocking then this function returns immediately, and if there are no connections queued the returned socket will be `InvalidSocket`. This function will raise EOS if an error occurs.

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

  Note: `client` must be initialised (with `new`), this function makes no effort to initialise the `client` variable.

  Warning: When using SSL with non-blocking sockets, it is best to use the acceptAddrSSL procedure as this procedure will most likely block.

    proc accept(server: TSocket; client: var TSocket) {.tags: [FReadIO],
        raises: [EOS].}

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

  Note: `client` must be initialised (with `new`), this function makes no effort to initialise the `client` variable.

    proc acceptAddr(server: TSocket): tuple[client: TSocket, address: string] {.
        deprecated, tags: [FReadIO], raises: [EOS].}

  Slightly different version of `acceptAddr`.

  Deprecated since version 0.9.0: Please use the function above.

    proc accept(server: TSocket): TSocket {.deprecated, tags: [FReadIO],
                                            raises: [EOS].}

  Deprecated since version 0.9.0: Please use the function above.

    proc close(socket: TSocket) {.raises: [], tags: [].}

  closes a socket.

    proc getServByName(name, proto: string): TServent {.tags: [FReadIO],
        raises: [EOS].}

  well-known getservbyname proc.

    proc getServByPort(port: TPort; proto: string): TServent {.tags: [FReadIO],
        raises: [EOS].}

  well-known getservbyport proc.

    proc getHostByAddr(ip: string): Thostent {.tags: [FReadIO], raises: [EOS].}

  This function will lookup the hostname of an IP Address.

    proc getHostByName(name: string): Thostent {.tags: [FReadIO], raises: [EOS].}

  well-known gethostbyname proc.

    proc getSockOptInt(socket: TSocket; level, optname: int): int {.tags: [FReadIO],
        raises: [EOS].}

  getsockopt for integer options.

    proc setSockOptInt(socket: TSocket; level, optname, optval: int) {.
        tags: [FWriteIO], raises: [EOS].}

  setsockopt for integer options.

    proc connect(socket: TSocket; address: string; port = TPort(0);
                 af: TDomain = AF_INET) {.tags: [FReadIO], raises: [EOS].}

  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.

    proc connectAsync(socket: TSocket; name: string; port = TPort(0);
                      af: TDomain = AF_INET) {.tags: [FReadIO], raises: [EOS].}

  A variant of `connect` for non-blocking sockets.

  This procedure will immediatelly return, it will not block until a connection is made. It is up to the caller to make sure the connection has been established by checking (using `select`) whether the socket is writeable.

  Note: For SSL sockets, the `handshake` procedure must be called whenever the socket successfully connects to a server.

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

  Determines whether a socket has data buffered.

    proc select(readfds, writefds, exceptfds: var seq[TSocket]; timeout = 500): int {.
        tags: [FReadIO], raises: [].}

  Traditional select function. This function will return the number of sockets that are ready to be read from, written to, or which have errors. If there are none; 0 is returned. `Timeout` is in miliseconds and -1 can be specified for no timeout.

  A socket is removed from the specific `seq` when it has data waiting to be read/written to or has errors (`exceptfds`).

    proc select(readfds, writefds: var seq[TSocket]; timeout = 500): int {.
        tags: [FReadIO], raises: [].}

  Variant of select with only a read and write list.

    proc selectWrite(writefds: var seq[TSocket]; timeout = 500): int {.
        tags: [FReadIO], raises: [].}

  When a socket in `writefds` is ready to be written to then a non-zero value will be returned specifying the count of the sockets which can be written to. The sockets which can be written to will also be removed from `writefds`.

  `timeout` is specified in miliseconds and `-1` can be specified for an unlimited time.

    proc select(readfds: var seq[TSocket]; timeout = 500): int {.raises: [],
        tags: [].}

  variant of select with a read list only

    proc recv(socket: TSocket; data: pointer; size: int): int {.tags: [FReadIO],
        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`.

    proc recv(socket: TSocket; data: pointer; size: int; timeout: int): int {.
        tags: [FReadIO, FTime], raises: [ETimeout, EOS].}

  overload with a `timeout` parameter in miliseconds.

    proc recv(socket: TSocket; data: var string; size: int; timeout = - 1): int {.
        raises: [ETimeout, EOS], tags: [FReadIO, FTime].}

  Higher-level version of `recv`.

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

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

  A timeout may be specified in miliseconds, if enough data is not received within the time specified an ETimeout exception will be raised.

  Note: `data` must be initialised.

    proc recvAsync(socket: TSocket; data: var string; size: int): int {.
        raises: [EOS], tags: [FReadIO].}

  Async version of `recv`.

  When socket is non-blocking and no data is available on the socket, `-1` will be returned and `data` will be `""`.

  Note: `data` must be initialised.

    proc recvLine(socket: TSocket; line: var TaintedString; timeout = - 1): bool {.
        tags: [FReadIO, FTime], deprecated, raises: [ETimeout, EOS].}

  Receive a line of data from `socket`.

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

  `True` is returned if data is available. `False` suggests an error, EOS exceptions are not raised and `False` is simply returned instead.

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

  A timeout can be specified in miliseconds, if data is not received within the specified time an ETimeout exception will be raised.

  Deprecated since version 0.9.2: This function has been deprecated in favour of readLine.

    proc readLine(socket: TSocket; line: var TaintedString; timeout = - 1) {.
        tags: [FReadIO, FTime], raises: [ETimeout, EOS].}

  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 EOS exception will be raised in the case of a socket error.

  A timeout can be specified in miliseconds, if data is not received within the specified time an ETimeout exception will be raised.

    proc recvLineAsync(socket: TSocket; line: var TaintedString): TRecvLineResult {.
        tags: [FReadIO], deprecated, raises: [].}

  Similar to `recvLine` but designed for non-blocking sockets.

  The values of the returned enum should be pretty self explanatory:

  > - If a full line has been retrieved; `RecvFullLine` is returned.
  > - If some data has been retrieved; `RecvPartialLine` is returned.
  > - If the socket has been disconnected; `RecvDisconnected` is returned.
  > - If call to `recv` failed; `RecvFail` is returned.

  Deprecated since version 0.9.2: This function has been deprecated in favour of readLineAsync.

    proc readLineAsync(socket: TSocket; line: var TaintedString): TReadLineResult {.
        tags: [FReadIO], raises: [EOS].}

  Similar to `recvLine` but designed for non-blocking sockets.

  The values of the returned enum should be pretty self explanatory:

  > - If a full line has been retrieved; `ReadFullLine` is returned.
  > - If some data has been retrieved; `ReadPartialLine` is returned.
  > - If the socket has been disconnected; `ReadDisconnected` is returned.
  > - If no data could be retrieved; `ReadNone` is returned.
  > - If call to `recv` failed; an EOS exception is raised.

    proc recv(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated,
        raises: [EOS].}

  receives all the available data from the socket. Socket errors will result in an `EOS` error. If socket is not a connectionless socket and socket is not connected `""` will be returned.

  Deprecated since version 0.9.2: This function is not safe for use.

    proc recvTimeout(socket: TSocket; timeout: int): TaintedString {.
        tags: [FReadIO], deprecated, raises: [ETimeout, EOS].}

  overloaded variant to support a `timeout` parameter, the `timeout` parameter specifies the amount of miliseconds to wait for data on the socket.

  Deprecated since version 0.9.2: This function is not safe for use.

    proc recvAsync(socket: TSocket; s: var TaintedString): bool {.tags: [FReadIO],
        deprecated, raises: [EOS].}

  receives all the data from a non-blocking socket. If socket is non-blocking and there are no messages available, False will be returned. Other socket errors will result in an `EOS` error. If socket is not a connectionless socket and socket is not connected `s` will be set to `""`.

  Deprecated since version 0.9.2: This function is not safe for use.

    proc recvFrom(socket: TSocket; data: var string; length: int;
                  address: var string; port: var TPort; flags = 0'i32): int {.
        tags: [FReadIO], raises: [].}

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

  If an error occurs the return value will be `-1`. 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.

    proc recvFromAsync(socket: TSocket; data: var string; length: int;
                       address: var string; port: var TPort; flags = 0'i32): bool {.
        tags: [FReadIO], raises: [EOS].}

  Variant of `recvFrom` for non-blocking sockets. Unlike `recvFrom`, this function will raise an EOS error whenever a socket error occurs.

  If there is no data to be read from the socket `False` will be returned.

    proc skip(socket: TSocket) {.tags: [FReadIO], deprecated, raises: [E_Base].}

  skips all the data that is pending for the socket

  Deprecated since version 0.9.2: This function is not safe for use.

    proc skip(socket: TSocket; size: int; timeout = - 1) {.
        raises: [E_Base, ETimeout, EOS], tags: [FTime, FReadIO].}

  Skips `size` amount of bytes.

  An optional timeout can be specified in miliseconds, if skipping the bytes takes longer than specified an ETimeout exception will be raised.

  Returns the number of skipped bytes.

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

  sends data to a socket.

    proc send(socket: TSocket; data: string) {.tags: [FWriteIO], raises: [EOS].}

  sends data to a socket.

    proc sendAsync(socket: TSocket; data: string): int {.tags: [FWriteIO],
        raises: [EOS].}

  sends data to a non-blocking socket. Returns `0` if no data could be sent, if data has been sent returns the amount of bytes of `data` that was successfully sent. This number may not always be the length of `data` but typically is.

  An EOS (or ESSL if socket is an SSL socket) exception is raised if an error occurs.

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

  safe alternative to `send`. Does not raise an EOS when an error occurs, and instead returns `false` on failure.

    proc sendTo(socket: TSocket; address: string; port: TPort; data: pointer;
                size: int; af: TDomain = AF_INET; flags = 0'i32): int {.
        tags: [FWriteIO], raises: [EOS].}

  low-level sendTo proc. 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.

  Note: This proc is not available for SSL sockets.

    proc sendTo(socket: TSocket; address: string; port: TPort; data: string): int {.
        tags: [FWriteIO], raises: [EOS].}

  Friendlier version of the low-level `sendTo`.

    proc setBlocking(s: TSocket; blocking: bool) {.tags: [], raises: [EOS].}

  sets blocking mode on socket

    proc connect(socket: TSocket; address: string; port = TPort(0); timeout: int;
                 af: TDomain = AF_INET) {.tags: [FReadIO, FWriteIO],
                                          raises: [EOS, ETimeout].}

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

  The `timeout` paremeter specifies the time in miliseconds to allow for the connection to the server to be made.

    proc isSSL(socket: TSocket): bool {.raises: [], tags: [].}

  Determines whether `socket` is a SSL socket.

    proc getFD(socket: TSocket): cint {.raises: [], tags: [].}

  Returns the socket's file descriptor

Generated: 2013-05-21 09:55:07 UTC