This module implements a simple portable type-safe sockets layer.
Most procedures raise EOS on error.
For OpenSSL support compile with -d:ssl. When using SSL be aware that most functions will then raise ESSL on SSL errors.
Types
ESSL* = object of ESynch
TSSLCVerifyMode* = enum CVerifyNone, CVerifyPeer
TSSLProtVersion* = enum protSSLv2, protSSLv3, protTLSv1, protSSLv23
PSSLContext* = distinct PSSLCTX
TSSLAcceptResult* = enum AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
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* {.pure, final.} = object name*: string aliases*: seq[string] port*: TPort proto*: string
- information about a service
Thostent* {.pure, final.} = 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
ETimeout* = object of ESynch
Lets
InvalidSocket*: TSocket = nil
- invalid socket
Procs
proc `==`*(a, b: TPort): bool {.borrow.}
- == for ports.
proc `$`*(p: TPort): string
- returns the port number as a string
proc ntohl*(x: int32): int32
- 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
- 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
- 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
- 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
- creates a new socket; returns InvalidSocket if an error occurs.
proc newContext*(protVersion = ProtSSLv23; verifyMode = CVerifyPeer; certFile = ""; keyFile = ""): PSSLContext
proc wrapSocket*(ctx: PSSLContext; socket: TSocket)
-
Creates a SSL context for socket and wraps the socket in it.
Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are are available with the addition of ProtSSLv23 which allows for compatibility with all of them.
There are currently only two options for verify mode; one is CVerifyNone and with it certificates will not be verified the other is CVerifyPeer and certificates will be verified for it, CVerifyPeer is the safest choice.
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:1024 -keyout mycert.pem -out mycert.pem.
Warning: Because SSL is meant to be secure I feel the need to warn you that this "wrapper" has not been thorougly tested and is therefore most likely very prone to security vulnerabilities.
proc listen*(socket: TSocket; backlog = SOMAXCONN)
- Marks socket as accepting connections. Backlog specifies the maximum length of the queue of pending connections.
proc parseIp4*(s: string): int32
- 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 = "")
- 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
- returns the socket's associated port number.
proc selectWrite*(writefds: var seq[TSocket]; timeout = 500): int
proc acceptAddr*(server: TSocket; client: var TSocket; address: var string)
-
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, this function makes no effort to initialise the client variable.
Warning: When using SSL with non-blocking sockets, it is best to use the acceptAddrAsync procedure as this procedure will most likely block.
proc setBlocking*(s: TSocket; blocking: bool)
proc acceptAddrSSL*(server: TSocket; client: var TSocket; address: var string): TSSLAcceptResult
-
This procedure should only be used for non-blocking SSL sockets. It will immediatelly return with one of the following values:
AcceptSuccess will be returned when a client has been successfully accepted and the handshake has been successfully performed between server and the newly connected client.
AcceptNoHandshake will be returned when a client has been accepted but no handshake could be performed. This can happen when the client connects but does not yet initiate a handshake. In this case acceptAddrSSL should be called again with the same parameters.
AcceptNoClient will be returned when no client is currently attempting to connect.
proc accept*(server: TSocket; client: var TSocket)
-
Equivalent to acceptAddr but doesn't return the address, only the socket.
Note: client must be initialised, this function makes no effort to initialise the client variable.
proc acceptAddr*(server: TSocket): tuple[client: TSocket, address: string] {. deprecated.}
-
Slightly different version of acceptAddr.
Deprecated since version 0.9.0: Please use the function above.
proc accept*(server: TSocket): TSocket {.deprecated.}
- Deprecated since version 0.9.0: Please use the function above.
proc close*(socket: TSocket)
- closes a socket.
proc getServByName*(name, proto: string): TServent
- well-known getservbyname proc.
proc getServByPort*(port: TPort; proto: string): TServent
- well-known getservbyport proc.
proc getHostByAddr*(ip: string): THostEnt
- This function will lookup the hostname of an IP Address.
proc getHostByName*(name: string): THostEnt
- well-known gethostbyname proc.
proc getSockOptInt*(socket: TSocket; level, optname: int): int
- getsockopt for integer options.
proc setSockOptInt*(socket: TSocket; level, optname, optval: int)
- setsockopt for integer options.
proc connect*(socket: TSocket; name: string; port = TPort(0); af: TDomain = AF_INET)
-
Connects socket to name:port. Name can be an IP address or a host name. If name 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)
-
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 handshake*(socket: TSocket): bool
-
This proc needs to be called on a socket after it connects. This is only applicable when using connectAsync. This proc performs the SSL handshake.
Returns False whenever the socket is not yet ready for a handshake, True whenever handshake completed successfully.
A ESSL error is raised on any other errors.
proc gotHandshake*(socket: TSocket): bool
-
Determines whether a handshake has occurred between a client - socket and the server that socket is connected to.
Throws ESSL if socket is not an SSL socket.
proc hasDataBuffered*(s: TSocket): bool
- Determines whether a socket has data buffered.
proc select*(readfds, writefds, exceptfds: var seq[TSocket]; timeout = 500): int
-
Traditional select function. This function will return the number of sockets that are ready, if none are ready; 0 is returned. Timeout is in miliseconds and -1 can be specified for no timeout.
You can determine whether a socket is ready by checking if it's still in one of the TSocket sequences.
proc select*(readfds, writefds: var seq[TSocket]; timeout = 500): int
proc selectWrite*(writefds: var seq[TSocket]; timeout = 500): int
proc select*(readfds: var seq[TSocket]; timeout = 500): int
proc recv*(socket: TSocket; data: pointer; size: int): int
- receives data from a socket
proc recv*(socket: TSocket; data: pointer; size: int; timeout: int): int
- overload with a timeout parameter in miliseconds.
proc recvLine*(socket: TSocket; line: var TaintedString): bool
-
retrieves a line 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 usually suggests an error, EOS exceptions are not raised in favour of this.
If the socket is disconnected, line will be set to "" and True will be returned.
Warning: Using this function on a unbuffered ssl socket will result in an error.
proc recvLine*(socket: TSocket; line: var TaintedString; timeout: int): bool
- variant with a timeout parameter, the timeout parameter specifies how many miliseconds to wait for data.
proc recvLineAsync*(socket: TSocket; line: var TaintedString): TRecvLineResult
- similar to recvLine but 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.
proc recv*(socket: TSocket): TaintedString
- receives all the 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.
proc recvTimeout*(socket: TSocket; timeout: int): TaintedString
- overloaded variant to support a timeout parameter, the timeout parameter specifies the amount of miliseconds to wait for data on the socket.
proc recvAsync*(socket: TSocket; s: var TaintedString): bool
- 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 "".
proc recvFrom*(socket: TSocket; data: var string; length: int; address: var string; port: var TPort; flags = 0'i32): int
-
Receives data from socket. This function should normally be used with connection-less sockets (UDP sockets).
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
- Similar to recvFrom but raises an EOS error when an error occurs. Returns False if no messages could be received from socket.
proc skip*(socket: TSocket)
- skips all the data that is pending for the socket
proc send*(socket: TSocket; data: pointer; size: int): int
- sends data to a socket.
proc send*(socket: TSocket; data: string)
- sends data to a socket.
proc sendAsync*(socket: TSocket; data: string): bool
- sends data to a non-blocking socket. Returns whether data was sent.
proc trySend*(socket: TSocket; data: string): bool
- 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
-
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
- Friendlier version of the low-level sendTo.
proc setBlocking*(s: TSocket; blocking: bool)
- sets blocking mode on socket
proc connect*(socket: TSocket; timeout: int; name: string; port = TPort(0); af: TDomain = AF_INET)
-
Overload for connect to support timeouts. The timeout parameter specifies the time in miliseconds of how long to wait for a connection to be made.
Warning: If socket is non-blocking then this function will set blocking mode on socket to true.
proc isSSL*(socket: TSocket): bool
- Determines whether socket is a SSL socket.
proc getFD*(socket: TSocket): cint
- Returns the socket's file descriptor