diff options
Diffstat (limited to 'lib/pure/sockets.nim')
-rwxr-xr-x | lib/pure/sockets.nim | 416 |
1 files changed, 0 insertions, 416 deletions
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim deleted file mode 100755 index 85628db78..000000000 --- a/lib/pure/sockets.nim +++ /dev/null @@ -1,416 +0,0 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2010 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements a simple portable type-safe sockets layer. - -import os - -when defined(Windows): - import winlean -else: - import posix - -# Note: The enumerations are mapped to Window's constants. - -type - TSocket* = distinct cint ## socket type - TPort* = distinct int16 ## port type - - TDomain* = enum ## domain, which specifies the protocol family of the - ## created socket. Other domains than those that are listed - ## here are unsupported. - 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. - - TType* = enum ## second argument to `socket` proc - 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, or - - TProtocol* = enum ## third argument to `socket` proc - 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. - - TServent* {.pure, final.} = object ## information about a service - name*: string - aliases*: seq[string] - port*: TPort - proto*: string - - Thostent* {.pure, final.} = object ## information about a given host - name*: string - aliases*: seq[string] - addrtype*: TDomain - length*: int - addrList*: seq[string] - -const - InvalidSocket* = TSocket(-1'i32) ## invalid socket number - -proc `==`*(a, b: TSocket): bool {.borrow.} - ## ``==`` for sockets. - -proc `==`*(a, b: TPort): bool {.borrow.} - ## ``==`` for ports. - -proc `$`*(p: TPort): string = - ## returns the port number as a string - result = $ze(int16(p)) - -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. - when cpuEndian == bigEndian: result = x - else: result = (x shr 24'i32) or - (x shr 8'i32 and 0xff00'i32) or - (x shl 8'i32 and 0xff0000'i32) or - (x shl 24'i32) - -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. - when cpuEndian == bigEndian: result = x - else: result = (x shr 8'i16) or (x shl 8'i16) - -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. - result = sockets.ntohl(x) - -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. - result = sockets.ntohs(x) - -when defined(Posix): - proc ToInt(domain: TDomain): cint = - case domain - of AF_UNIX: result = posix.AF_UNIX - of AF_INET: result = posix.AF_INET - of AF_INET6: result = posix.AF_INET6 - else: nil - - proc ToInt(typ: TType): cint = - case typ - of SOCK_STREAM: result = posix.SOCK_STREAM - of SOCK_DGRAM: result = posix.SOCK_DGRAM - of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET - of SOCK_RAW: result = posix.SOCK_RAW - else: nil - - proc ToInt(p: TProtocol): cint = - case p - of IPPROTO_TCP: result = posix.IPPROTO_TCP - of IPPROTO_UDP: result = posix.IPPROTO_UDP - of IPPROTO_IP: result = posix.IPPROTO_IP - of IPPROTO_IPV6: result = posix.IPPROTO_IPV6 - of IPPROTO_RAW: result = posix.IPPROTO_RAW - of IPPROTO_ICMP: result = posix.IPPROTO_ICMP - else: nil - -else: - proc toInt(domain: TDomain): cint = - result = toU16(ord(domain)) - - proc ToInt(typ: TType): cint = - result = cint(ord(typ)) - - proc ToInt(p: TProtocol): cint = - result = cint(ord(p)) - -proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, - protocol: TProtocol = IPPROTO_TCP): TSocket = - ## creates a new socket; returns `InvalidSocket` if an error occurs. - when defined(Windows): - result = TSocket(winlean.socket(ord(domain), ord(typ), ord(protocol))) - else: - result = TSocket(posix.socket(ToInt(domain), ToInt(typ), ToInt(protocol))) - -proc listen*(socket: TSocket, attempts = 5) = - ## listens to socket. - if listen(cint(socket), cint(attempts)) < 0'i32: OSError() - -proc bindAddr*(socket: TSocket, port = TPort(0)) = - ## binds a port number to a socket. - var name: Tsockaddr_in - when defined(Windows): - name.sin_family = int16(ord(AF_INET)) - else: - name.sin_family = posix.AF_INET - name.sin_port = sockets.htons(int16(port)) - name.sin_addr.s_addr = sockets.htonl(INADDR_ANY) - if bindSocket(cint(socket), cast[ptr TSockAddr](addr(name)), - sizeof(name)) < 0'i32: - OSError() - -proc getSockName*(socket: TSocket): TPort = - ## returns the socket's associated port number. - var name: Tsockaddr_in - when defined(Windows): - name.sin_family = int16(ord(AF_INET)) - else: - name.sin_family = posix.AF_INET - #name.sin_port = htons(cint16(port)) - #name.sin_addr.s_addr = htonl(INADDR_ANY) - var namelen: cint = sizeof(name) - if getsockname(cint(socket), cast[ptr TSockAddr](addr(name)), - addr(namelen)) == -1'i32: - OSError() - result = TPort(sockets.ntohs(name.sin_port)) - -proc accept*(server: TSocket): TSocket = - ## waits for a client and returns its socket - var client: Tsockaddr_in - var clientLen: cint = sizeof(client) - result = TSocket(accept(cint(server), cast[ptr TSockAddr](addr(client)), - addr(clientLen))) - -proc close*(socket: TSocket) = - ## closes a socket. - when defined(windows): - discard winlean.closeSocket(cint(socket)) - else: - discard posix.close(cint(socket)) - -proc getServByName*(name, proto: string): TServent = - ## well-known getservbyname proc. - when defined(Windows): - var s = winlean.getservbyname(name, proto) - else: - var s = posix.getservbyname(name, proto) - if s == nil: OSError() - result.name = $s.s_name - result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = TPort(s.s_port) - result.proto = $s.s_proto - -proc getServByPort*(port: TPort, proto: string): TServent = - ## well-known getservbyport proc. - when defined(Windows): - var s = winlean.getservbyport(ze(int16(port)), proto) - else: - var s = posix.getservbyport(ze(int16(port)), proto) - if s == nil: OSError() - result.name = $s.s_name - result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = TPort(s.s_port) - result.proto = $s.s_proto - -proc getHostByName*(name: string): THostEnt = - ## well-known gethostbyname proc. - when defined(Windows): - var s = winlean.gethostbyname(name) - else: - var s = posix.gethostbyname(name) - if s == nil: OSError() - result.name = $s.h_name - result.aliases = cstringArrayToSeq(s.h_aliases) - when defined(windows): - result.addrType = TDomain(s.h_addrtype) - else: - if s.h_addrtype == posix.AF_INET: - result.addrType = AF_INET - elif s.h_addrtype == posix.AF_INET6: - result.addrType = AF_INET6 - else: - OSError("unknown h_addrtype") - result.addrList = cstringArrayToSeq(s.h_addr_list) - result.length = int(s.h_length) - -proc getSockOptInt*(socket: TSocket, level, optname: int): int = - ## getsockopt for integer options. - var res: cint - var size: cint = sizeof(res) - if getsockopt(cint(socket), cint(level), cint(optname), - addr(res), addr(size)) < 0'i32: - OSError() - result = int(res) - -proc setSockOptInt*(socket: TSocket, level, optname, optval: int) = - ## setsockopt for integer options. - var value = cint(optval) - if setsockopt(cint(socket), cint(level), cint(optname), addr(value), - sizeof(value)) < 0'i32: - OSError() - -proc connect*(socket: TSocket, name: string, port = TPort(0), - af: TDomain = AF_INET) = - ## well-known connect operation. Already does ``htons`` on the port number, - ## so you shouldn't do it. `name` can be an IP address or a host name of the - ## form "force7.de". - var hints: TAddrInfo - var aiList: ptr TAddrInfo = nil - hints.ai_family = toInt(af) - hints.ai_socktype = toInt(SOCK_STREAM) - hints.ai_protocol = toInt(IPPROTO_TCP) - if getAddrInfo(name, $port, addr(hints), aiList) != 0'i32: OSError() - # try all possibilities: - var success = false - var it = aiList - while it != nil: - if connect(cint(socket), it.ai_addr, it.ai_addrlen) == 0'i32: - success = true - break - it = it.ai_next - freeaddrinfo(aiList) - if not success: OSError() - - when false: - var s: TSockAddrIn - s.sin_addr.s_addr = inet_addr(name) - s.sin_port = sockets.htons(int16(port)) - when defined(windows): - s.sin_family = toU16(ord(af)) - else: - case af - of AF_UNIX: s.sin_family = posix.AF_UNIX - of AF_INET: s.sin_family = posix.AF_INET - of AF_INET6: s.sin_family = posix.AF_INET6 - else: nil - if connect(cint(socket), cast[ptr TSockAddr](addr(s)), sizeof(s)) < 0'i32: - OSError() - -#proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint, -# fromm: ptr TSockAddr, fromlen: ptr cint): cint - -#proc sendto*(s: TWinSocket, buf: cstring, len, flags: cint, -# to: ptr TSockAddr, tolen: cint): cint - -proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) = - FD_ZERO(fd) - for i in items(s): - m = max(m, int(i)) - FD_SET(cint(i), fd) - -proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) = - var i = 0 - var L = s.len - while i < L: - if FD_ISSET(cint(s[i]), fd) != 0'i32: - s[i] = s[L-1] - dec(L) - else: - inc(i) - setLen(s, L) - -proc select*(readfds, writefds, exceptfds: var seq[TSocket], - timeout = 500): int = - ## select with a sensible Nimrod interface. `timeout` is in miliseconds. - var tv: TTimeVal - tv.tv_sec = 0 - tv.tv_usec = timeout * 1000 - - var rd, wr, ex: TFdSet - var m = 0 - createFdSet((rd), readfds, m) - createFdSet((wr), writefds, m) - createFdSet((ex), exceptfds, m) - - result = int(select(cint(m), addr(rd), addr(wr), addr(ex), addr(tv))) - - pruneSocketSet(readfds, (rd)) - pruneSocketSet(writefds, (wr)) - pruneSocketSet(exceptfds, (ex)) - -proc select*(readfds, writefds: var seq[TSocket], - timeout = 500): int = - ## select with a sensible Nimrod interface. `timeout` is in miliseconds. - var tv: TTimeVal - tv.tv_sec = 0 - tv.tv_usec = timeout * 1000 - - var rd, wr: TFdSet - var m = 0 - createFdSet((rd), readfds, m) - createFdSet((wr), writefds, m) - - result = int(select(cint(m), addr(rd), addr(wr), nil, addr(tv))) - - pruneSocketSet(readfds, (rd)) - pruneSocketSet(writefds, (wr)) - - -proc select*(readfds: var seq[TSocket], timeout = 500): int = - ## select with a sensible Nimrod interface. `timeout` is in miliseconds. - var tv: TTimeVal - tv.tv_sec = 0 - tv.tv_usec = timeout * 1000 - - var rd: TFdSet - var m = 0 - createFdSet((rd), readfds, m) - - result = int(select(cint(m), addr(rd), nil, nil, addr(tv))) - - pruneSocketSet(readfds, (rd)) - - -proc recvLine*(socket: TSocket, line: var string): bool = - ## returns false if no further data is available. `line` must be initalized - ## and not nil! - setLen(line, 0) - while true: - var c: char - var n = recv(cint(socket), addr(c), 1, 0'i32) - if n <= 0: return - if c == '\r': - n = recv(cint(socket), addr(c), 1, MSG_PEEK) - if n > 0 and c == '\L': - discard recv(cint(socket), addr(c), 1, 0'i32) - elif n <= 0: return false - return true - elif c == '\L': return true - add(line, c) - -proc recv*(socket: TSocket, data: pointer, size: int): int = - ## receives data from a socket - result = recv(cint(socket), data, size, 0'i32) - -proc recv*(socket: TSocket): string = - ## receives all the data from the socket - const bufSize = 200 - var buf = newString(bufSize) - result = "" - while true: - var bytesRead = recv(socket, cstring(buf), bufSize-1) - buf[bytesRead] = '\0' # might not be necessary - setLen(buf, bytesRead) - add(result, buf) - if bytesRead != bufSize-1: break - -proc skip*(socket: TSocket) = - ## skips all the data that is pending for the socket - const bufSize = 200 - var buf = alloc(bufSize) - while recv(socket, buf, bufSize) == bufSize: nil - dealloc(buf) - -proc send*(socket: TSocket, data: pointer, size: int): int = - ## sends data to a socket. - result = send(cint(socket), data, size, 0'i32) - -proc send*(socket: TSocket, data: string) = - ## sends data to a socket. - if send(socket, cstring(data), data.len) != data.len: OSError() - -when defined(Windows): - var wsa: TWSADATA - if WSAStartup(0x0101'i16, wsa) != 0: OSError() - - |