Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
fcabc0f9f4
6 changed files with 223 additions and 38 deletions
|
|
@ -455,6 +455,9 @@ type
|
||||||
TInPort* = int16 ## unsigned!
|
TInPort* = int16 ## unsigned!
|
||||||
TInAddrScalar* = int32 ## unsigned!
|
TInAddrScalar* = int32 ## unsigned!
|
||||||
|
|
||||||
|
TInAddrT* {.importc: "in_addr_t", pure, final,
|
||||||
|
header: "<netinet/in.h>".} = int32 ## unsigned!
|
||||||
|
|
||||||
TInAddr* {.importc: "struct in_addr", pure, final,
|
TInAddr* {.importc: "struct in_addr", pure, final,
|
||||||
header: "<netinet/in.h>".} = object ## struct in_addr
|
header: "<netinet/in.h>".} = object ## struct in_addr
|
||||||
s_addr*: TInAddrScalar
|
s_addr*: TInAddrScalar
|
||||||
|
|
@ -544,6 +547,7 @@ type
|
||||||
|
|
||||||
var
|
var
|
||||||
errno* {.importc, header: "<errno.h>".}: cint ## error variable
|
errno* {.importc, header: "<errno.h>".}: cint ## error variable
|
||||||
|
h_errno* {.importc, header: "<netdb.h>".}: cint
|
||||||
daylight* {.importc, header: "<time.h>".}: cint
|
daylight* {.importc, header: "<time.h>".}: cint
|
||||||
timezone* {.importc, header: "<time.h>".}: int
|
timezone* {.importc, header: "<time.h>".}: int
|
||||||
|
|
||||||
|
|
@ -1558,6 +1562,8 @@ var
|
||||||
## Terminates a record (if supported by the protocol).
|
## Terminates a record (if supported by the protocol).
|
||||||
MSG_OOB* {.importc, header: "<sys/socket.h>".}: cint
|
MSG_OOB* {.importc, header: "<sys/socket.h>".}: cint
|
||||||
## Out-of-band data.
|
## Out-of-band data.
|
||||||
|
MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
|
||||||
|
## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected.
|
||||||
MSG_PEEK* {.importc, header: "<sys/socket.h>".}: cint
|
MSG_PEEK* {.importc, header: "<sys/socket.h>".}: cint
|
||||||
## Leave received data in queue.
|
## Leave received data in queue.
|
||||||
MSG_TRUNC* {.importc, header: "<sys/socket.h>".}: cint
|
MSG_TRUNC* {.importc, header: "<sys/socket.h>".}: cint
|
||||||
|
|
@ -1733,8 +1739,8 @@ proc htons*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".}
|
||||||
proc ntohl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".}
|
proc ntohl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".}
|
||||||
proc ntohs*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".}
|
proc ntohs*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".}
|
||||||
|
|
||||||
proc inet_addr*(a1: cstring): int32 {.importc, header: "<arpa/inet.h>".}
|
proc inet_addr*(a1: cstring): TInAddrT {.importc, header: "<arpa/inet.h>".}
|
||||||
proc inet_ntoa*(a1: int32): cstring {.importc, header: "<arpa/inet.h>".}
|
proc inet_ntoa*(a1: TInAddr): cstring {.importc, header: "<arpa/inet.h>".}
|
||||||
proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {.
|
proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {.
|
||||||
importc, header: "<arpa/inet.h>".}
|
importc, header: "<arpa/inet.h>".}
|
||||||
proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {.
|
proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {.
|
||||||
|
|
@ -2315,6 +2321,7 @@ proc sched_setscheduler*(a1: tpid, a2: cint, a3: var tsched_param): cint {.
|
||||||
proc sched_yield*(): cint {.importc, header: "<sched.h>".}
|
proc sched_yield*(): cint {.importc, header: "<sched.h>".}
|
||||||
|
|
||||||
proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".}
|
proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".}
|
||||||
|
proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
|
||||||
|
|
||||||
proc FD_CLR*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
|
proc FD_CLR*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
|
||||||
proc FD_ISSET*(a1: cint, a2: var Tfd_set): cint {.
|
proc FD_ISSET*(a1: cint, a2: var Tfd_set): cint {.
|
||||||
|
|
|
||||||
|
|
@ -495,7 +495,7 @@ type
|
||||||
JArray
|
JArray
|
||||||
|
|
||||||
PJsonNode* = ref TJsonNode ## JSON node
|
PJsonNode* = ref TJsonNode ## JSON node
|
||||||
TJsonNode {.final, pure.} = object
|
TJsonNode* {.final, pure.} = object
|
||||||
case kind*: TJsonNodeKind
|
case kind*: TJsonNodeKind
|
||||||
of JString:
|
of JString:
|
||||||
str*: String
|
str*: String
|
||||||
|
|
|
||||||
|
|
@ -88,30 +88,35 @@ proc close*(s: var TScgiState) =
|
||||||
## closes the connection.
|
## closes the connection.
|
||||||
s.server.close()
|
s.server.close()
|
||||||
|
|
||||||
proc next*(s: var TScgistate) =
|
proc next*(s: var TScgistate, timeout: int = -1): bool =
|
||||||
## proceed to the first/next request.
|
## proceed to the first/next request. Waits ``timeout`` miliseconds for a
|
||||||
s.client = accept(s.server)
|
## request, if ``timeout`` is `-1` then this function will never time out.
|
||||||
var L = 0
|
## Returns `True` if a new request has been processed.
|
||||||
while true:
|
var rsocks = @[s.server]
|
||||||
var d = s.client.recvChar()
|
if select(rsocks, timeout) == 1 and rsocks.len == 0:
|
||||||
if d notin strutils.digits:
|
s.client = accept(s.server)
|
||||||
if d != ':': scgiError("':' after length expected")
|
var L = 0
|
||||||
break
|
while true:
|
||||||
L = L * 10 + ord(d) - ord('0')
|
var d = s.client.recvChar()
|
||||||
recvBuffer(s, L+1)
|
if d notin strutils.digits:
|
||||||
s.headers = parseHeaders(s.input, L)
|
if d != ':': scgiError("':' after length expected")
|
||||||
if s.headers["SCGI"] != "1": scgiError("SCGI Version 1 expected")
|
break
|
||||||
L = parseInt(s.headers["CONTENT_LENGTH"])
|
L = L * 10 + ord(d) - ord('0')
|
||||||
recvBuffer(s, L)
|
recvBuffer(s, L+1)
|
||||||
|
s.headers = parseHeaders(s.input, L)
|
||||||
|
if s.headers["SCGI"] != "1": scgiError("SCGI Version 1 expected")
|
||||||
|
L = parseInt(s.headers["CONTENT_LENGTH"])
|
||||||
|
recvBuffer(s, L)
|
||||||
|
return True
|
||||||
|
|
||||||
proc writeStatusOkTextContent*(c: TSocket) =
|
proc writeStatusOkTextContent*(c: TSocket, contentType = "text/html") =
|
||||||
## sends the following string to the socket `c`::
|
## sends the following string to the socket `c`::
|
||||||
##
|
##
|
||||||
## Status: 200 OK\r\LContent-Type: text/plain\r\L\r\L
|
## Status: 200 OK\r\LContent-Type: text/html\r\L\r\L
|
||||||
##
|
##
|
||||||
## You should send this before sending your HTML page, for example.
|
## You should send this before sending your HTML page, for example.
|
||||||
c.send("Status: 200 OK\r\L" &
|
c.send("Status: 200 OK\r\L" &
|
||||||
"Content-Type: text/plain\r\L\r\L")
|
"Content-Type: $1\r\L\r\L" % contentType)
|
||||||
|
|
||||||
proc run*(handleRequest: proc (client: TSocket, input: string,
|
proc run*(handleRequest: proc (client: TSocket, input: string,
|
||||||
headers: PStringTable): bool,
|
headers: PStringTable): bool,
|
||||||
|
|
@ -121,9 +126,9 @@ proc run*(handleRequest: proc (client: TSocket, input: string,
|
||||||
s.open(port)
|
s.open(port)
|
||||||
var stop = false
|
var stop = false
|
||||||
while not stop:
|
while not stop:
|
||||||
next(s)
|
if next(s):
|
||||||
stop = handleRequest(s.client, s.input, s.headers)
|
stop = handleRequest(s.client, s.input, s.headers)
|
||||||
s.client.close()
|
s.client.close()
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
|
|
|
||||||
|
|
@ -223,12 +223,22 @@ proc getSockName*(socket: TSocket): TPort =
|
||||||
result = TPort(sockets.ntohs(name.sin_port))
|
result = TPort(sockets.ntohs(name.sin_port))
|
||||||
|
|
||||||
proc accept*(server: TSocket): TSocket =
|
proc accept*(server: TSocket): TSocket =
|
||||||
## waits for a client and returns its socket
|
## waits for a client and returns its socket. ``InvalidSocket`` is returned
|
||||||
|
## if an error occurs, or if ``server`` is non-blocking and there are no
|
||||||
|
## clients connecting.
|
||||||
var client: Tsockaddr_in
|
var client: Tsockaddr_in
|
||||||
var clientLen: cint = sizeof(client)
|
var clientLen: cint = sizeof(client)
|
||||||
result = TSocket(accept(cint(server), cast[ptr TSockAddr](addr(client)),
|
result = TSocket(accept(cint(server), cast[ptr TSockAddr](addr(client)),
|
||||||
addr(clientLen)))
|
addr(clientLen)))
|
||||||
|
|
||||||
|
proc acceptAddr*(server: TSocket): tuple[sock: TSocket, address: string] =
|
||||||
|
## waits for a client and returns its socket and IP address
|
||||||
|
var address: Tsockaddr_in
|
||||||
|
var addrLen: cint = sizeof(address)
|
||||||
|
var sock = TSocket(accept(cint(server), cast[ptr TSockAddr](addr(address)),
|
||||||
|
addr(addrLen)))
|
||||||
|
return (sock, $inet_ntoa(address.sin_addr))
|
||||||
|
|
||||||
proc close*(socket: TSocket) =
|
proc close*(socket: TSocket) =
|
||||||
## closes a socket.
|
## closes a socket.
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -260,6 +270,35 @@ proc getServByPort*(port: TPort, proto: string): TServent =
|
||||||
result.port = TPort(s.s_port)
|
result.port = TPort(s.s_port)
|
||||||
result.proto = $s.s_proto
|
result.proto = $s.s_proto
|
||||||
|
|
||||||
|
proc getHostByAddr*(ip: string): THostEnt =
|
||||||
|
## This function will lookup the hostname of an IP Address.
|
||||||
|
var myaddr: TInAddr
|
||||||
|
myaddr.s_addr = inet_addr(ip)
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr),
|
||||||
|
cint(sockets.AF_INET))
|
||||||
|
if s == nil: OSError()
|
||||||
|
else:
|
||||||
|
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr),
|
||||||
|
cint(posix.AF_INET))
|
||||||
|
if s == nil:
|
||||||
|
raise newException(EOS, $hStrError(h_errno))
|
||||||
|
|
||||||
|
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 getHostByName*(name: string): THostEnt =
|
proc getHostByName*(name: string): THostEnt =
|
||||||
## well-known gethostbyname proc.
|
## well-known gethostbyname proc.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
|
|
@ -299,9 +338,10 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) =
|
||||||
|
|
||||||
proc connect*(socket: TSocket, name: string, port = TPort(0),
|
proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||||
af: TDomain = AF_INET) =
|
af: TDomain = AF_INET) =
|
||||||
## well-known connect operation. Already does ``htons`` on the port number,
|
## Connects socket to ``name``:``port``. ``Name`` can be an IP address or a
|
||||||
## so you shouldn't do it. `name` can be an IP address or a host name of the
|
## host name. If ``name`` is a host name, this function will try each IP
|
||||||
## form "force7.de".
|
## of that host name. ``htons`` is already performed on ``port`` so you must
|
||||||
|
## not do it.
|
||||||
var hints: TAddrInfo
|
var hints: TAddrInfo
|
||||||
var aiList: ptr TAddrInfo = nil
|
var aiList: ptr TAddrInfo = nil
|
||||||
hints.ai_family = toInt(af)
|
hints.ai_family = toInt(af)
|
||||||
|
|
@ -316,6 +356,7 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||||
success = true
|
success = true
|
||||||
break
|
break
|
||||||
it = it.ai_next
|
it = it.ai_next
|
||||||
|
|
||||||
freeaddrinfo(aiList)
|
freeaddrinfo(aiList)
|
||||||
if not success: OSError()
|
if not success: OSError()
|
||||||
|
|
||||||
|
|
@ -334,6 +375,40 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||||
if connect(cint(socket), cast[ptr TSockAddr](addr(s)), sizeof(s)) < 0'i32:
|
if connect(cint(socket), cast[ptr TSockAddr](addr(s)), sizeof(s)) < 0'i32:
|
||||||
OSError()
|
OSError()
|
||||||
|
|
||||||
|
proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||||
|
af: TDomain = AF_INET) =
|
||||||
|
## A variant of ``connect`` for non-blocking sockets.
|
||||||
|
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:
|
||||||
|
var ret = connect(cint(socket), it.ai_addr, it.ai_addrlen)
|
||||||
|
if ret == 0'i32:
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# TODO: Test on Windows.
|
||||||
|
when defined(windows):
|
||||||
|
var err = WSAGetLastError()
|
||||||
|
# Windows EINTR doesn't behave same as POSIX.
|
||||||
|
if err == WSAEWOULDBLOCK:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if errno == EINTR or errno == EINPROGRESS:
|
||||||
|
return
|
||||||
|
|
||||||
|
it = it.ai_next
|
||||||
|
|
||||||
|
freeaddrinfo(aiList)
|
||||||
|
if not success: OSError()
|
||||||
|
|
||||||
|
|
||||||
#proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint,
|
#proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint,
|
||||||
# fromm: ptr TSockAddr, fromlen: ptr cint): cint
|
# fromm: ptr TSockAddr, fromlen: ptr cint): cint
|
||||||
|
|
||||||
|
|
@ -360,6 +435,7 @@ proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) =
|
||||||
proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
||||||
timeout = 500): int =
|
timeout = 500): int =
|
||||||
## select with a sensible Nimrod interface. `timeout` is in miliseconds.
|
## select with a sensible Nimrod interface. `timeout` is in miliseconds.
|
||||||
|
## Specify -1 for no timeout.
|
||||||
var tv: TTimeVal
|
var tv: TTimeVal
|
||||||
tv.tv_sec = 0
|
tv.tv_sec = 0
|
||||||
tv.tv_usec = timeout * 1000
|
tv.tv_usec = timeout * 1000
|
||||||
|
|
@ -370,7 +446,10 @@ proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
||||||
createFdSet((wr), writefds, m)
|
createFdSet((wr), writefds, m)
|
||||||
createFdSet((ex), exceptfds, m)
|
createFdSet((ex), exceptfds, m)
|
||||||
|
|
||||||
result = int(select(cint(m), addr(rd), addr(wr), addr(ex), addr(tv)))
|
if timeout != -1:
|
||||||
|
result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
|
||||||
|
else:
|
||||||
|
result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), nil))
|
||||||
|
|
||||||
pruneSocketSet(readfds, (rd))
|
pruneSocketSet(readfds, (rd))
|
||||||
pruneSocketSet(writefds, (wr))
|
pruneSocketSet(writefds, (wr))
|
||||||
|
|
@ -379,6 +458,7 @@ proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
||||||
proc select*(readfds, writefds: var seq[TSocket],
|
proc select*(readfds, writefds: var seq[TSocket],
|
||||||
timeout = 500): int =
|
timeout = 500): int =
|
||||||
## select with a sensible Nimrod interface. `timeout` is in miliseconds.
|
## select with a sensible Nimrod interface. `timeout` is in miliseconds.
|
||||||
|
## Specify -1 for no timeout.
|
||||||
var tv: TTimeVal
|
var tv: TTimeVal
|
||||||
tv.tv_sec = 0
|
tv.tv_sec = 0
|
||||||
tv.tv_usec = timeout * 1000
|
tv.tv_usec = timeout * 1000
|
||||||
|
|
@ -388,14 +468,37 @@ proc select*(readfds, writefds: var seq[TSocket],
|
||||||
createFdSet((rd), readfds, m)
|
createFdSet((rd), readfds, m)
|
||||||
createFdSet((wr), writefds, m)
|
createFdSet((wr), writefds, m)
|
||||||
|
|
||||||
result = int(select(cint(m), addr(rd), addr(wr), nil, addr(tv)))
|
if timeout != -1:
|
||||||
|
result = int(select(cint(m+1), addr(rd), addr(wr), nil, addr(tv)))
|
||||||
|
else:
|
||||||
|
result = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
|
||||||
|
|
||||||
pruneSocketSet(readfds, (rd))
|
pruneSocketSet(readfds, (rd))
|
||||||
pruneSocketSet(writefds, (wr))
|
pruneSocketSet(writefds, (wr))
|
||||||
|
|
||||||
|
proc selectWrite*(writefds: var seq[TSocket],
|
||||||
|
timeout = 500): int =
|
||||||
|
## select with a sensible Nimrod interface. `timeout` is in miliseconds.
|
||||||
|
## Specify -1 for no timeout.
|
||||||
|
var tv: TTimeVal
|
||||||
|
tv.tv_sec = 0
|
||||||
|
tv.tv_usec = timeout * 1000
|
||||||
|
|
||||||
|
var wr: TFdSet
|
||||||
|
var m = 0
|
||||||
|
createFdSet((wr), writefds, m)
|
||||||
|
|
||||||
|
if timeout != -1:
|
||||||
|
result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv)))
|
||||||
|
else:
|
||||||
|
result = int(select(cint(m+1), nil, addr(wr), nil, nil))
|
||||||
|
|
||||||
|
pruneSocketSet(writefds, (wr))
|
||||||
|
|
||||||
|
|
||||||
proc select*(readfds: var seq[TSocket], timeout = 500): int =
|
proc select*(readfds: var seq[TSocket], timeout = 500): int =
|
||||||
## select with a sensible Nimrod interface. `timeout` is in miliseconds.
|
## select with a sensible Nimrod interface. `timeout` is in miliseconds.
|
||||||
|
## Specify -1 for no timeout.
|
||||||
var tv: TTimeVal
|
var tv: TTimeVal
|
||||||
tv.tv_sec = 0
|
tv.tv_sec = 0
|
||||||
tv.tv_usec = timeout * 1000
|
tv.tv_usec = timeout * 1000
|
||||||
|
|
@ -404,14 +507,18 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
|
||||||
var m = 0
|
var m = 0
|
||||||
createFdSet((rd), readfds, m)
|
createFdSet((rd), readfds, m)
|
||||||
|
|
||||||
result = int(select(cint(m), addr(rd), nil, nil, addr(tv)))
|
if timeout != -1:
|
||||||
|
result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
|
||||||
|
else:
|
||||||
|
result = int(select(cint(m+1), addr(rd), nil, nil, nil))
|
||||||
|
|
||||||
pruneSocketSet(readfds, (rd))
|
pruneSocketSet(readfds, (rd))
|
||||||
|
|
||||||
|
|
||||||
proc recvLine*(socket: TSocket, line: var string): bool =
|
proc recvLine*(socket: TSocket, line: var string): bool =
|
||||||
## returns false if no further data is available. `line` must be initalized
|
## returns false if no further data is available. `Line` must be initialized
|
||||||
## and not nil!
|
## and not nil! This does not throw an EOS exception, therefore
|
||||||
|
## it can be used in both blocking and non-blocking sockets.
|
||||||
setLen(line, 0)
|
setLen(line, 0)
|
||||||
while true:
|
while true:
|
||||||
var c: char
|
var c: char
|
||||||
|
|
@ -431,17 +538,53 @@ proc recv*(socket: TSocket, data: pointer, size: int): int =
|
||||||
result = recv(cint(socket), data, size, 0'i32)
|
result = recv(cint(socket), data, size, 0'i32)
|
||||||
|
|
||||||
proc recv*(socket: TSocket): string =
|
proc recv*(socket: TSocket): string =
|
||||||
## receives all the data from the socket
|
## 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.
|
||||||
const bufSize = 200
|
const bufSize = 200
|
||||||
var buf = newString(bufSize)
|
var buf = newString(bufSize)
|
||||||
result = ""
|
result = ""
|
||||||
while true:
|
while true:
|
||||||
var bytesRead = recv(socket, cstring(buf), bufSize-1)
|
var bytesRead = recv(socket, cstring(buf), bufSize-1)
|
||||||
|
# Error
|
||||||
|
if bytesRead == -1: OSError()
|
||||||
|
|
||||||
buf[bytesRead] = '\0' # might not be necessary
|
buf[bytesRead] = '\0' # might not be necessary
|
||||||
setLen(buf, bytesRead)
|
setLen(buf, bytesRead)
|
||||||
add(result, buf)
|
add(result, buf)
|
||||||
if bytesRead != bufSize-1: break
|
if bytesRead != bufSize-1: break
|
||||||
|
|
||||||
|
proc recvAsync*(socket: TSocket, s: var string): 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 ``""``.
|
||||||
|
const bufSize = 200
|
||||||
|
var buf = newString(bufSize)
|
||||||
|
s = ""
|
||||||
|
while true:
|
||||||
|
var bytesRead = recv(socket, cstring(buf), bufSize-1)
|
||||||
|
# Error
|
||||||
|
if bytesRead == -1:
|
||||||
|
when defined(windows):
|
||||||
|
# TODO: Test on Windows
|
||||||
|
var err = WSAGetLastError()
|
||||||
|
if err == WSAEWOULDBLOCK:
|
||||||
|
return False
|
||||||
|
else: OSError()
|
||||||
|
else:
|
||||||
|
if errno == EAGAIN or errno == EWOULDBLOCK:
|
||||||
|
return False
|
||||||
|
else: OSError()
|
||||||
|
|
||||||
|
buf[bytesRead] = '\0' # might not be necessary
|
||||||
|
setLen(buf, bytesRead)
|
||||||
|
add(s, buf)
|
||||||
|
if bytesRead != bufSize-1: break
|
||||||
|
result = True
|
||||||
|
|
||||||
proc skip*(socket: TSocket) =
|
proc skip*(socket: TSocket) =
|
||||||
## skips all the data that is pending for the socket
|
## skips all the data that is pending for the socket
|
||||||
const bufSize = 200
|
const bufSize = 200
|
||||||
|
|
@ -451,12 +594,30 @@ proc skip*(socket: TSocket) =
|
||||||
|
|
||||||
proc send*(socket: TSocket, data: pointer, size: int): int =
|
proc send*(socket: TSocket, data: pointer, size: int): int =
|
||||||
## sends data to a socket.
|
## sends data to a socket.
|
||||||
result = send(cint(socket), data, size, 0'i32)
|
when defined(windows):
|
||||||
|
result = send(cint(socket), data, size, 0'i32)
|
||||||
|
else:
|
||||||
|
result = send(cint(socket), data, size, int32(MSG_NOSIGNAL))
|
||||||
|
|
||||||
proc send*(socket: TSocket, data: string) =
|
proc send*(socket: TSocket, data: string) =
|
||||||
## sends data to a socket.
|
## sends data to a socket.
|
||||||
if send(socket, cstring(data), data.len) != data.len: OSError()
|
if send(socket, cstring(data), data.len) != data.len: OSError()
|
||||||
|
|
||||||
|
proc sendAsync*(socket: TSocket, data: string) =
|
||||||
|
## sends data to a non-blocking socket.
|
||||||
|
var bytesSent = send(socket, cstring(data), data.len)
|
||||||
|
if bytesSent == -1:
|
||||||
|
when defined(windows):
|
||||||
|
var err = WSAGetLastError()
|
||||||
|
# TODO: Test on windows.
|
||||||
|
if err == WSAEINPROGRESS:
|
||||||
|
return
|
||||||
|
else: OSError()
|
||||||
|
else:
|
||||||
|
if errno == EAGAIN or errno == EWOULDBLOCK:
|
||||||
|
return
|
||||||
|
else: OSError()
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
const
|
const
|
||||||
SOCKET_ERROR = -1
|
SOCKET_ERROR = -1
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,11 @@ const
|
||||||
|
|
||||||
ws2dll = "Ws2_32.dll"
|
ws2dll = "Ws2_32.dll"
|
||||||
|
|
||||||
|
WSAEWOULDBLOCK* = 10035
|
||||||
|
WSAEINPROGRESS* = 10036
|
||||||
|
|
||||||
|
proc WSAGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
|
||||||
|
|
||||||
type
|
type
|
||||||
TWSAData* {.pure, final.} = object
|
TWSAData* {.pure, final.} = object
|
||||||
wVersion, wHighVersion: int16
|
wVersion, wHighVersion: int16
|
||||||
|
|
@ -297,6 +302,9 @@ proc getservbyname*(name, proto: cstring): ptr TServent {.
|
||||||
proc getservbyport*(port: cint, proto: cstring): ptr TServent {.
|
proc getservbyport*(port: cint, proto: cstring): ptr TServent {.
|
||||||
stdcall, importc: "getservbyport", dynlib: ws2dll.}
|
stdcall, importc: "getservbyport", dynlib: ws2dll.}
|
||||||
|
|
||||||
|
proc gethostbyaddr*(ip: ptr TInAddr, len: cint, theType: cint): ptr THostEnt {.
|
||||||
|
stdcall, importc: "gethostbyaddr", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc gethostbyname*(name: cstring): ptr THostEnt {.
|
proc gethostbyname*(name: cstring): ptr THostEnt {.
|
||||||
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
|
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
|
||||||
|
|
||||||
|
|
@ -373,4 +381,5 @@ proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,
|
||||||
proc freeaddrinfo*(ai: ptr TAddrInfo) {.
|
proc freeaddrinfo*(ai: ptr TAddrInfo) {.
|
||||||
stdcall, importc: "freeaddrinfo", dynlib: ws2dll.}
|
stdcall, importc: "freeaddrinfo", dynlib: ws2dll.}
|
||||||
|
|
||||||
|
proc inet_ntoa*(i: TInAddr): cstring {.
|
||||||
|
stdcall, importc, dynlib: ws2dll.}
|
||||||
|
|
|
||||||
|
|
@ -7469,6 +7469,9 @@ proc iter_nth_child*(tree_model: PTreeModel, iter: PTreeIter,
|
||||||
proc iter_parent*(tree_model: PTreeModel, iter: PTreeIter,
|
proc iter_parent*(tree_model: PTreeModel, iter: PTreeIter,
|
||||||
child: PTreeIter): gboolean{.cdecl, dynlib: lib,
|
child: PTreeIter): gboolean{.cdecl, dynlib: lib,
|
||||||
importc: "gtk_tree_model_iter_parent".}
|
importc: "gtk_tree_model_iter_parent".}
|
||||||
|
proc get_string_from_iter*(tree_model: PTreeModel, iter: PTreeIter):
|
||||||
|
cstring{.cdecl, dynlib: lib,
|
||||||
|
importc: "gtk_tree_model_get_string_from_iter".}
|
||||||
proc ref_node*(tree_model: PTreeModel, iter: PTreeIter){.cdecl,
|
proc ref_node*(tree_model: PTreeModel, iter: PTreeIter){.cdecl,
|
||||||
dynlib: lib, importc: "gtk_tree_model_ref_node".}
|
dynlib: lib, importc: "gtk_tree_model_ref_node".}
|
||||||
proc unref_node*(tree_model: PTreeModel, iter: PTreeIter){.cdecl,
|
proc unref_node*(tree_model: PTreeModel, iter: PTreeIter){.cdecl,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue