Skip to content

Commit 11ae9c2

Browse files
committed
robust reentrant buffers
1 parent a07113c commit 11ae9c2

File tree

2 files changed

+53
-21
lines changed

2 files changed

+53
-21
lines changed

lib/pure/nativesockets.nim

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ when hostOS == "solaris":
2525
const useWinVersion = defined(windows) or defined(nimdoc)
2626
const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or
2727
defined(nuttx)
28+
const smallBufInitSize = when defined(testReentrantBufs): 1 else: 1024
29+
const largeBufInitSize = when defined(testReentrantBufs): 1 else: 4096
2830

2931
when useWinVersion:
3032
import std/winlean
@@ -223,13 +225,12 @@ proc getProtoByName*(name: string): int {.since: (1, 3, 5).} =
223225
res: ptr ptr posix.Protoent): cint
224226
{.importc, header: "<netdb.h>".}
225227
var pe: posix.Protoent
226-
var bufSize = 1024
228+
var buf = newString(smallBufInitSize)
227229
while true:
228-
var buf = newSeq[char](bufSize)
229230
let ret = getprotobyname_r(name.cstring, addr pe,
230-
cast[cstring](addr buf[0]), csize_t(bufSize), addr protoent)
231+
buf.cstring, csize_t(buf.len), addr protoent)
231232
if ret != ERANGE: break
232-
bufSize *= 2
233+
buf.setLen(buf.len * 2)
233234
{.emit: ";\n#else".}
234235
protoent = posix.getprotobyname(name.cstring)
235236
{.emit: ";\n#endif".}
@@ -392,13 +393,12 @@ when not useNimNetLite:
392393
elif defined(linux) and not defined(android):
393394
var se: posix.Servent
394395
var s: ptr posix.Servent
395-
var bufSize = 1024
396+
var buf = newString(smallBufInitSize)
396397
while true:
397-
var buf = newSeq[char](bufSize)
398398
let ret = getservbyname_r(name.cstring, proto.cstring, addr se,
399-
cast[cstring](addr buf[0]), csize_t(bufSize), addr s)
399+
buf.cstring, csize_t(buf.len), addr s)
400400
if ret != ERANGE: break
401-
bufSize *= 2
401+
buf.setLen(buf.len * 2)
402402
else:
403403
var s = posix.getservbyname(name, proto)
404404
if s == nil: raiseOSError(osLastError(), "Service not found.")
@@ -420,13 +420,12 @@ when not useNimNetLite:
420420
elif defined(linux) and not defined(android):
421421
var se: posix.Servent
422422
var s: ptr posix.Servent
423-
var bufSize = 1024
423+
var buf = newString(smallBufInitSize)
424424
while true:
425-
var buf = newSeq[char](bufSize)
426425
let ret = getservbyport_r(uint16(port).cint, proto.cstring, addr se,
427-
cast[cstring](addr buf[0]), csize_t(bufSize), addr s)
426+
buf.cstring, csize_t(buf.len), addr s)
428427
if ret != ERANGE: break
429-
bufSize *= 2
428+
buf.setLen(buf.len * 2)
430429
else:
431430
var s = posix.getservbyport(uint16(port).cint, proto)
432431
if s == nil: raiseOSError(osLastError(), "Service not found.")
@@ -466,21 +465,20 @@ when not useNimNetLite:
466465
var he: posix.Hostent
467466
var h_errnop: cint
468467
var s: ptr posix.Hostent
469-
var bufSize = 4096
468+
var buf = newString(largeBufInitSize)
470469
while true:
471-
var buf = newSeq[char](bufSize)
472470
when defined(android4):
473471
let ret = gethostbyaddr_r(cast[cstring](myAddr), addrLen.SockLen,
474472
cint(family), addr he,
475-
cast[cstring](addr buf[0]), csize_t(bufSize),
473+
buf.cstring, csize_t(buf.len),
476474
addr s, addr h_errnop)
477475
else:
478476
let ret = gethostbyaddr_r(myAddr, addrLen.SockLen,
479477
cint(family), addr he,
480-
cast[cstring](addr buf[0]), csize_t(bufSize),
478+
buf.cstring, csize_t(buf.len),
481479
addr s, addr h_errnop)
482480
if ret != ERANGE: break
483-
bufSize *= 2
481+
buf.setLen(buf.len * 2)
484482
if s == nil:
485483
raiseOSError(osLastError(), $hstrerror(h_errnop))
486484
else:
@@ -534,14 +532,13 @@ when not useNimNetLite:
534532
var he: posix.Hostent
535533
var h_errnop: cint
536534
var s: ptr posix.Hostent
537-
var bufSize = 4096
535+
var buf = newString(largeBufInitSize)
538536
while true:
539-
var buf = newSeq[char](bufSize)
540537
let ret = gethostbyname_r(name.cstring, addr he,
541-
cast[cstring](addr buf[0]), csize_t(bufSize),
538+
buf.cstring, csize_t(buf.len),
542539
addr s, addr h_errnop)
543540
if ret != ERANGE: break
544-
bufSize *= 2
541+
buf.setLen(buf.len * 2)
545542
if s == nil:
546543
raiseOSError(osLastError(), $hstrerror(h_errnop))
547544
else:
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
discard """
2+
matrix: "--mm:refc -d:testReentrantBufs; --mm:orc -d:testReentrantBufs"
3+
joinable: false
4+
"""
5+
6+
## Tests that the _r network calls handle ERANGE buffer resizing correctly.
7+
## Compiled with -d:testReentrantBufs which sets initial buffers to 1 byte,
8+
## forcing the while-loop to grow buffers through several ERANGE iterations.
9+
10+
import std/nativesockets
11+
import std/assertions
12+
13+
when defined(linux):
14+
block: # getProtoByName
15+
doAssert getProtoByName("tcp") == 6
16+
doAssert getProtoByName("udp") == 17
17+
18+
block: # getServByName
19+
let s = getServByName("http", "tcp")
20+
doAssert s.name == "http"
21+
doAssert s.proto == "tcp"
22+
23+
block: # getServByPort
24+
let s = getServByPort(Port(htons(80)), "tcp")
25+
doAssert s.name == "http"
26+
doAssert s.proto == "tcp"
27+
28+
block: # getHostByName
29+
let he = getHostByName("localhost")
30+
doAssert he.name.len > 0
31+
doAssert he.addrList.len > 0
32+
33+
block: # getHostByAddr
34+
let he = getHostByAddr("127.0.0.1")
35+
doAssert he.name.len > 0

0 commit comments

Comments
 (0)