sockets module complete
This commit is contained in:
parent
55e900bba2
commit
fb2ae12c49
13 changed files with 716 additions and 238 deletions
43
lib/pure/browsers.nim
Executable file
43
lib/pure/browsers.nim
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#
|
||||
#
|
||||
# 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 proc for opening URLs with the user's
|
||||
## default browser.
|
||||
|
||||
import strutils
|
||||
|
||||
when defined(windows):
|
||||
import winlean
|
||||
else:
|
||||
import os, osproc
|
||||
|
||||
proc openDefaultBrowser*(url: string) =
|
||||
## opens `url` with the user's default browser. This does not block.
|
||||
##
|
||||
## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open``
|
||||
## command is used. Under Unix, it is checked if ``gnome-open`` exists and
|
||||
## used if it does. Next attempt is ``kde-open``, then ``xdg-open``.
|
||||
## Otherwise the environment variable ``BROWSER`` is used to determine the
|
||||
## default browser to use.
|
||||
when defined(windows):
|
||||
discard ShellExecute(0'i32, "open", url, nil, nil, SW_SHOWNORMAL)
|
||||
elif defined(macosx):
|
||||
discard execShellCmd("open " & quoteIfContainsWhite(url))
|
||||
else:
|
||||
const attempts = ["gnome-open ", "kde-open ", "xdg-open "]
|
||||
var u = quoteIfContainsWhite(url)
|
||||
for a in items(attempts):
|
||||
if execShellCmd(a & u) == 0: return
|
||||
for b in getEnv("BROWSER").split(PathSep):
|
||||
try:
|
||||
# we use ``startProcess`` here because we don't want to block!
|
||||
discard startProcess(command=b, args=[url], options={poUseShell})
|
||||
return
|
||||
except EOS:
|
||||
nil
|
||||
|
|
@ -120,51 +120,57 @@ proc getEncodedData(allowedMethods: set[TRequestMethod]): string =
|
|||
if methodNone notin allowedMethods:
|
||||
cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'")
|
||||
|
||||
iterator decodeData*(data: string): tuple[key, value: string] =
|
||||
## Reads and decodes CGI data and yields the (name, value) pairs the
|
||||
## data consists of.
|
||||
var i = 0
|
||||
var name = ""
|
||||
var value = ""
|
||||
# decode everything in one pass:
|
||||
while data[i] != '\0':
|
||||
setLen(name, 0) # reuse memory
|
||||
while true:
|
||||
case data[i]
|
||||
of '\0': break
|
||||
of '%':
|
||||
var x = 0
|
||||
handleHexChar(data[i+1], x)
|
||||
handleHexChar(data[i+2], x)
|
||||
inc(i, 2)
|
||||
add(name, chr(x))
|
||||
of '+': add(name, ' ')
|
||||
of '=', '&': break
|
||||
else: add(name, data[i])
|
||||
inc(i)
|
||||
if data[i] != '=': cgiError("'=' expected")
|
||||
inc(i) # skip '='
|
||||
setLen(value, 0) # reuse memory
|
||||
while true:
|
||||
case data[i]
|
||||
of '%':
|
||||
var x = 0
|
||||
handleHexChar(data[i+1], x)
|
||||
handleHexChar(data[i+2], x)
|
||||
inc(i, 2)
|
||||
add(value, chr(x))
|
||||
of '+': add(value, ' ')
|
||||
of '&', '\0': break
|
||||
else: add(value, data[i])
|
||||
inc(i)
|
||||
yield (name, value)
|
||||
if data[i] == '&': inc(i)
|
||||
elif data[i] == '\0': break
|
||||
else: cgiError("'&' expected")
|
||||
|
||||
iterator decodeData*(allowedMethods: set[TRequestMethod] =
|
||||
{methodNone, methodPost, methodGet}): tuple[key, value: string] =
|
||||
## Reads and decodes CGI data and yields the (name, value) pairs the
|
||||
## data consists of. If the client does not use a method listed in the
|
||||
## `allowedMethods` set, an `ECgi` exception is raised.
|
||||
var enc = getEncodedData(allowedMethods)
|
||||
if not isNil(enc):
|
||||
# decode everything in one pass:
|
||||
var i = 0
|
||||
var name = ""
|
||||
var value = ""
|
||||
while enc[i] != '\0':
|
||||
setLen(name, 0) # reuse memory
|
||||
while true:
|
||||
case enc[i]
|
||||
of '\0': break
|
||||
of '%':
|
||||
var x = 0
|
||||
handleHexChar(enc[i+1], x)
|
||||
handleHexChar(enc[i+2], x)
|
||||
inc(i, 2)
|
||||
add(name, chr(x))
|
||||
of '+': add(name, ' ')
|
||||
of '=', '&': break
|
||||
else: add(name, enc[i])
|
||||
inc(i)
|
||||
if enc[i] != '=': cgiError("'=' expected")
|
||||
inc(i) # skip '='
|
||||
setLen(value, 0) # reuse memory
|
||||
while true:
|
||||
case enc[i]
|
||||
of '%':
|
||||
var x = 0
|
||||
handleHexChar(enc[i+1], x)
|
||||
handleHexChar(enc[i+2], x)
|
||||
inc(i, 2)
|
||||
add(value, chr(x))
|
||||
of '+': add(value, ' ')
|
||||
of '&', '\0': break
|
||||
else: add(value, enc[i])
|
||||
inc(i)
|
||||
yield (name, value)
|
||||
if enc[i] == '&': inc(i)
|
||||
elif enc[i] == '\0': break
|
||||
else: cgiError("'&' expected")
|
||||
var data = getEncodedData(allowedMethods)
|
||||
if not isNil(data):
|
||||
for key, value in decodeData(data):
|
||||
yield key, value
|
||||
|
||||
proc readData*(allowedMethods: set[TRequestMethod] =
|
||||
{methodNone, methodPost, methodGet}): PStringTable =
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ proc cmpPaths*(pathA, pathB: string): int {.noSideEffect.} =
|
|||
proc sameFile*(path1, path2: string): bool =
|
||||
## Returns True if both pathname arguments refer to the same file or
|
||||
## directory (as indicated by device number and i-node number).
|
||||
## Raises an exception if an os.stat() call on either pathname fails.
|
||||
## Raises an exception if an stat() call on either pathname fails.
|
||||
when defined(Windows):
|
||||
var
|
||||
a, b: TWin32FindData
|
||||
|
|
|
|||
|
|
@ -7,26 +7,7 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements a simple portable type-safe sockets layer. **Note**:
|
||||
## This module is incomplete and probably buggy. It does not work on Windows
|
||||
## yet. Help if you are interested.
|
||||
|
||||
# TODO:
|
||||
# getservbyname(name, proto)
|
||||
# getservbyport(port, proto)
|
||||
# gethostbyname(name)
|
||||
# gethostbyaddr(addr)
|
||||
# shutdown(sock, how)
|
||||
# connect(sock, address, port)
|
||||
# select({ socket, ... }, timeout)
|
||||
|
||||
# sendto
|
||||
# recvfrom
|
||||
|
||||
# bind(socket, address, port)
|
||||
|
||||
# getsockopt(socket, level, optname)
|
||||
# setsockopt(socket, level, optname, value)
|
||||
## This module implements a simple portable type-safe sockets layer.
|
||||
|
||||
import os
|
||||
|
||||
|
|
@ -35,6 +16,8 @@ when defined(Windows):
|
|||
else:
|
||||
import posix
|
||||
|
||||
# Note: The enumerations are mapped to Window's constants.
|
||||
|
||||
type
|
||||
TSocket* = distinct cint ## socket type
|
||||
TPort* = distinct int16 ## port type
|
||||
|
|
@ -42,87 +25,149 @@ 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).
|
||||
AF_INET, ## for network protocol IPv4 or
|
||||
AF_INET6 ## for network protocol IPv6.
|
||||
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, ## reliable stream-oriented service or Stream Sockets
|
||||
SOCK_DGRAM, ## datagram service or Datagram Sockets
|
||||
SOCK_SEQPACKET, ## reliable sequenced packet service, or
|
||||
SOCK_RAW ## raw protocols atop the network layer.
|
||||
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, ## Transmission control protocol.
|
||||
IPPROTO_UDP, ## User datagram protocol.
|
||||
IPPROTO_IP, ## Internet protocol.
|
||||
IPPROTO_IPV6, ## Internet Protocol Version 6.
|
||||
IPPROTO_RAW, ## Raw IP Packets Protocol.
|
||||
IPPROTO_ICMP ## Control message protocol.
|
||||
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 = result = $ze(int16(p))
|
||||
proc `$`*(p: TPort): string =
|
||||
## returns the port number as a string
|
||||
result = $ze(int16(p))
|
||||
|
||||
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
|
||||
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 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
|
||||
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 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
|
||||
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 socket*(domain: TDomain = AF_INET6, typ: TType = SOCK_STREAM,
|
||||
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
|
||||
|
||||
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.
|
||||
result = TSocket(posix.socket(ToInt(domain), ToInt(typ), ToInt(protocol)))
|
||||
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 posix.listen(cint(socket), cint(attempts)) < 0'i32: OSError()
|
||||
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
|
||||
name.sin_family = posix.AF_INET
|
||||
name.sin_port = htons(int16(port))
|
||||
name.sin_addr.s_addr = htonl(INADDR_ANY)
|
||||
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
|
||||
name.sin_family = posix.AF_INET
|
||||
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(ntohs(name.sin_port))
|
||||
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: TsockLen = sizeof(client)
|
||||
var clientLen: cint = sizeof(client)
|
||||
result = TSocket(accept(cint(server), cast[ptr TSockAddr](addr(client)),
|
||||
addr(clientLen)))
|
||||
|
||||
|
|
@ -133,8 +178,163 @@ proc close*(socket: TSocket) =
|
|||
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.
|
||||
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.
|
||||
## returns false if no further data is available. `line` must be initalized
|
||||
## and not nil!
|
||||
setLen(line, 0)
|
||||
while true:
|
||||
var c: char
|
||||
|
|
@ -150,11 +350,11 @@ proc recvLine*(socket: TSocket, line: var string): bool =
|
|||
add(line, c)
|
||||
|
||||
proc recv*(socket: TSocket, data: pointer, size: int): int =
|
||||
## receive data from a socket
|
||||
result = posix.recv(cint(socket), data, size, 0'i32)
|
||||
## receives data from a socket
|
||||
result = recv(cint(socket), data, size, 0'i32)
|
||||
|
||||
proc recv*(socket: TSocket): string =
|
||||
## receive all the data from the socket
|
||||
## receives all the data from the socket
|
||||
const bufSize = 200
|
||||
var buf = newString(bufSize)
|
||||
result = ""
|
||||
|
|
@ -173,36 +373,15 @@ proc skip*(socket: TSocket) =
|
|||
dealloc(buf)
|
||||
|
||||
proc send*(socket: TSocket, data: pointer, size: int): int =
|
||||
result = posix.send(cint(socket), data, size, 0'i32)
|
||||
## 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()
|
||||
|
||||
proc ntohl*(x: int32): int32 =
|
||||
## Convert 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)
|
||||
when defined(Windows):
|
||||
var wsa: TWSADATA
|
||||
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
||||
|
||||
proc ntohs*(x: int16): int16 =
|
||||
## Convert 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 =
|
||||
## Convert 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 =
|
||||
## Convert 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)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -655,8 +655,7 @@ proc replace*(s: string, sub, by: char): string =
|
|||
proc delete*(s: var string, first, last: int) =
|
||||
## Deletes in `s` the characters at position `first`..`last`. This modifies
|
||||
## `s` itself, it does not return a copy.
|
||||
var
|
||||
i = first
|
||||
var i = first
|
||||
# example: "abc___uvwxyz\0" (___ is to be deleted)
|
||||
# --> first == 3, last == 5
|
||||
# s[first..] = s[last+1..]
|
||||
|
|
@ -851,6 +850,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string =
|
|||
proc validEmailAddress*(s: string): bool =
|
||||
## returns true if `s` seems to be a valid e-mail address.
|
||||
## The checking also uses a domain list.
|
||||
## Note: This will be moved into another module soon.
|
||||
const
|
||||
chars = Letters + Digits + {'!','#','$','%','&',
|
||||
'\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue