Add Zephyr Support (#19003)

* Porting Nim to run on Zephyr.

Includes changes to `std/net`.

Squashed commit of the following:
    tweaking more memory / malloc things
    revert back bitmasks
    tweaking nim to use kernel heap as C malloc doesn't work
    fixing socket polling on zephyr
    cleanup getting maximum sockets for process or for rtos'es
    reorganizing and fixing net for async / system
    merge netlite changes back into nativesockets
    merge netlite changes back into nativesockets
    reverting native sockets back
    tweaking nim / zephyr network
    adding option to run 'net-lite' from linux
    bridging zephyr's max connections
    fixing net errors
    fixing compilation with getAddrString
    fixing compilation with getAddrString
    experimenting with a nativesockets_lite ... getAddrString
    experimenting with a nativesockets_lite ... getAddrString
    experimenting with a nativesockets_lite ... getLocalAddr
    experimenting with a nativesockets_lite ... getLocalAddr
    experimenting with a nativesockets_lite ...
    add note regarding incorrect FreeRTOS Sockadd_in fields
    changing to NIM_STATIC_ASSERT
    cleaning up the static_assert error messages
    cleaning up the static_assert error messages
    setting up static assert ftw!
    testing compile time asserts
    reworking Sockaddr objects to more closely match various platforms
    reworking Sockaddr objects to more closely match various platforms
    reworking Sockaddr objects to more closely match various platforms
    finding missing items (issue  #18684)
    fixup posix constants (issue  #18684)
    adding plumbing for zephyr os (issue  #18684)
    adding plumbing for zephyr os (issue  #18684)

* fixing constant capitalizations

* remove extra debug prints and fix TSa_Family/cint issue

* remove extra debug prints and fix TSa_Family/cint issue

* Porting Nim to run on Zephyr.

Includes changes to `std/net`.

Squashed commit of the following:
    tweaking more memory / malloc things
    revert back bitmasks
    tweaking nim to use kernel heap as C malloc doesn't work
    fixing socket polling on zephyr
    cleanup getting maximum sockets for process or for rtos'es
    reorganizing and fixing net for async / system
    merge netlite changes back into nativesockets
    merge netlite changes back into nativesockets
    reverting native sockets back
    tweaking nim / zephyr network
    adding option to run 'net-lite' from linux
    bridging zephyr's max connections
    fixing net errors
    fixing compilation with getAddrString
    fixing compilation with getAddrString
    experimenting with a nativesockets_lite ... getAddrString
    experimenting with a nativesockets_lite ... getAddrString
    experimenting with a nativesockets_lite ... getLocalAddr
    experimenting with a nativesockets_lite ... getLocalAddr
    experimenting with a nativesockets_lite ...
    add note regarding incorrect FreeRTOS Sockadd_in fields
    changing to NIM_STATIC_ASSERT
    cleaning up the static_assert error messages
    cleaning up the static_assert error messages
    setting up static assert ftw!
    testing compile time asserts
    reworking Sockaddr objects to more closely match various platforms
    reworking Sockaddr objects to more closely match various platforms
    reworking Sockaddr objects to more closely match various platforms
    finding missing items (issue  #18684)
    fixup posix constants (issue  #18684)
    adding plumbing for zephyr os (issue  #18684)
    adding plumbing for zephyr os (issue  #18684)

* fixing constant capitalizations

* remove extra debug prints and fix TSa_Family/cint issue

* remove extra debug prints and fix TSa_Family/cint issue

* fixing PR issues

* Porting Nim to run on Zephyr.

Includes changes to `std/net`.

Squashed commit of the following:
    tweaking more memory / malloc things
    revert back bitmasks
    tweaking nim to use kernel heap as C malloc doesn't work
    fixing socket polling on zephyr
    cleanup getting maximum sockets for process or for rtos'es
    reorganizing and fixing net for async / system
    merge netlite changes back into nativesockets
    merge netlite changes back into nativesockets
    reverting native sockets back
    tweaking nim / zephyr network
    adding option to run 'net-lite' from linux
    bridging zephyr's max connections
    fixing net errors
    fixing compilation with getAddrString
    fixing compilation with getAddrString
    experimenting with a nativesockets_lite ... getAddrString
    experimenting with a nativesockets_lite ... getAddrString
    experimenting with a nativesockets_lite ... getLocalAddr
    experimenting with a nativesockets_lite ... getLocalAddr
    experimenting with a nativesockets_lite ...
    add note regarding incorrect FreeRTOS Sockadd_in fields
    changing to NIM_STATIC_ASSERT
    cleaning up the static_assert error messages
    cleaning up the static_assert error messages
    setting up static assert ftw!
    testing compile time asserts
    reworking Sockaddr objects to more closely match various platforms
    reworking Sockaddr objects to more closely match various platforms
    reworking Sockaddr objects to more closely match various platforms
    finding missing items (issue  #18684)
    fixup posix constants (issue  #18684)
    adding plumbing for zephyr os (issue  #18684)
    adding plumbing for zephyr os (issue  #18684)

* fixing constant capitalizations

* remove extra debug prints and fix TSa_Family/cint issue

* remove extra debug prints and fix TSa_Family/cint issue

* Remerge

* fixing constant capitalizations

* remove extra debug prints and fix TSa_Family/cint issue

* remove extra debug prints and fix TSa_Family/cint issue

* fixing PR issues

* fix maxDescriptors on zephyr/freertos

* move maxDescriptors to selector.nim -- fixes compile issue

* change realloc impl on zephyr to match ansi c behavior

* change realloc impl on zephyr to match ansi c behavior

* force compileOnly mode for tlwip

Co-authored-by: Jaremy J. Creechley <jaremy.creechley@wavebaselabs.com>
Co-authored-by: Jaremy Creechley <jaremy.creechley@panthalassa.com>
(cherry picked from commit 141b76e365)
This commit is contained in:
Jaremy Creechley
2021-10-24 09:51:57 +00:00
committed by narimiran
parent b741f3cbd3
commit 1dc47696c0
20 changed files with 522 additions and 346 deletions

View File

@@ -597,7 +597,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
osQnx, osAtari, osAix,
osHaiku, osVxWorks, osSolaris, osNetbsd,
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos}
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr}
of "linux":
result = conf.target.targetOS in {osLinux, osAndroid}
of "bsd":
@@ -617,6 +617,8 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
result = conf.target.targetOS == osNintendoSwitch
of "freertos", "lwip":
result = conf.target.targetOS == osFreeRTOS
of "zephyr":
result = conf.target.targetOS == osZephyr
of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian
of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian
of "cpu8": result = CPU[conf.target.targetCPU].bit == 8

View File

@@ -22,7 +22,7 @@ type
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos, osAix, osPalmos, osQnx,
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr, osAny
type
TInfoOSProp* = enum
@@ -185,6 +185,10 @@ const
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {ospPosix}),
(name: "Zephyr", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {ospPosix}),
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",

View File

@@ -151,8 +151,10 @@ proc htons*(a1: uint16): uint16 {.importc, header: "<arpa/inet.h>".}
proc ntohl*(a1: uint32): uint32 {.importc, header: "<arpa/inet.h>".}
proc ntohs*(a1: uint16): uint16 {.importc, header: "<arpa/inet.h>".}
proc inet_addr*(a1: cstring): InAddrT {.importc, header: "<arpa/inet.h>".}
proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "<arpa/inet.h>".}
when not defined(zephyr):
proc inet_addr*(a1: cstring): InAddrT {.importc, header: "<arpa/inet.h>".}
proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "<arpa/inet.h>".}
proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {.
importc:"(char *)$1", header: "<arpa/inet.h>".}
proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {.

View File

@@ -363,6 +363,8 @@ var SEM_FAILED* {.importc: "SEM_FAILED", header: "<semaphore.h>".}: pointer
# <sys/resource.h>
# var RLIMIT_NOFILE* {.importc: "RLIMIT_NOFILE", header: "<sys/resource.h>".}: cint
var FD_MAX* {.importc: "CONFIG_LWIP_MAX_SOCKETS", header: "<lwipopts.h>".}: cint
# <sys/select.h>
var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "<sys/select.h>".}: cint

View File

@@ -10,7 +10,7 @@
when defined(nimHasStyleChecks):
{.push styleChecks: off.}
when defined(freertos):
when defined(freertos) or defined(zephyr):
const
hasSpawnH = false # should exist for every Posix system nowadays
hasAioH = false
@@ -391,9 +391,29 @@ when hasSpawnH:
header: "<spawn.h>", final, pure.} = object
when defined(linux):
const Sockaddr_max_length* = 255
# from sys/un.h
const Sockaddr_un_path_length* = 108
elif defined(zephyr):
when defined(net_ipv6):
const Sockaddr_max_length* = 24
elif defined(net_raw):
const Sockaddr_max_length* = 20
else:
const Sockaddr_max_length* = 8
const Sockaddr_un_path_length* = Sockaddr_max_length
# Zephyr is heavily customizable so it's easy to get to a state
# where Nim & Zephyr IPv6 settings are out of sync, causing painful runtime failures.
{.emit: ["NIM_STATIC_ASSERT(NET_SOCKADDR_MAX_SIZE == ",
Sockaddr_max_length,
",\"NET_SOCKADDR_MAX_SIZE and Sockaddr_max_length size mismatch!",
" Check that Nim and Zephyr IPv4/IPv6 settings match.",
" Try adding -d:net_ipv6 to enable IPv6 for Nim on Zephyr.\" );"].}
elif defined(freertos) or defined(lwip):
const Sockaddr_max_length* = 14
const Sockaddr_un_path_length* = 108
else:
const Sockaddr_max_length* = 255
# according to http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/un.h.html
# this is >=92
const Sockaddr_un_path_length* = 92
@@ -408,48 +428,50 @@ when defined(lwip):
pure, final.} = object ## struct sockaddr
sa_len*: uint8 ## Address family.
sa_family*: TSa_Family ## Address family.
sa_data*: array[0..255, char] ## Socket address (variable-length data).
sa_data*: array[0..Sockaddr_max_length-sizeof(uint8)-sizeof(TSa_Family), char] ## Socket address (variable-length data).
Sockaddr_storage* {.importc: "struct sockaddr_storage",
header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr_storage
s2_len*: uint8 ## Address family.
ss_family*: TSa_Family ## Address family.
s2_data1*: array[2, char] ## Address family.
s2_data2*: array[3, uint32] ## Address family.
when defined(lwip6) or defined(net_ipv6):
s2_data3*: array[3, uint32] ## Address family.
elif defined(zephyr):
type
SockAddr* {.importc: "struct sockaddr", header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr
sa_family*: TSa_Family ## Address family.
data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data).
Sockaddr_storage* {.importc: "struct sockaddr_storage",
header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr_storage
ss_family*: TSa_Family ## Address family.
data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data).
{.emit: ["NIM_STATIC_ASSERT(sizeof(struct sockaddr) == ", sizeof(Sockaddr), ",\"struct size mismatch\" );"].}
{.emit: ["NIM_STATIC_ASSERT(sizeof(struct sockaddr_storage) == ", sizeof(Sockaddr_storage), ",\"struct size mismatch\" );"].}
else:
type
SockAddr* {.importc: "struct sockaddr", header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr
sa_family*: TSa_Family ## Address family.
sa_data*: array[0..255, char] ## Socket address (variable-length data).
sa_data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data).
Sockaddr_storage* {.importc: "struct sockaddr_storage",
header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr_storage
ss_family*: TSa_Family ## Address family.
type
Sockaddr_un* {.importc: "struct sockaddr_un", header: "<sys/un.h>",
pure, final.} = object ## struct sockaddr_un
sun_family*: TSa_Family ## Address family.
sun_path*: array[0..Sockaddr_un_path_length-1, char] ## Socket path
sun_path*: array[0..Sockaddr_un_path_length-sizeof(TSa_Family), char] ## Socket path
when defined(lwip):
when not defined(lwip6):
type
Sockaddr_storage* {.importc: "struct sockaddr_storage",
header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr_storage
s2_len*: uint8 ## Address family.
ss_family*: TSa_Family ## Address family.
s2_data1*: array[2, char] ## Address family.
s2_data2*: array[3, uint32] ## Address family.
else:
type
Sockaddr_storage* {.importc: "struct sockaddr_storage",
header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr_storage
s2_len*: uint8 ## Address family.
ss_family*: TSa_Family ## Address family.
s2_data1*: array[2, char] ## Address family.
s2_data2*: array[3, uint32] ## Address family.
s2_data3*: array[3, uint32] ## Address family.
else:
type
Sockaddr_storage* {.importc: "struct sockaddr_storage",
header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr_storage
ss_family*: TSa_Family ## Address family.
type
Tif_nameindex* {.importc: "struct if_nameindex", final,
pure, header: "<net/if.h>".} = object ## struct if_nameindex
@@ -494,6 +516,7 @@ type
header: "<netinet/in.h>".} = object ## struct in_addr
s_addr*: InAddrScalar
# TODO: Fixme for FreeRTOS/LwIP, these are incorrect
Sockaddr_in* {.importc: "struct sockaddr_in", pure, final,
header: "<netinet/in.h>".} = object ## struct sockaddr_in
sin_family*: TSa_Family ## AF_INET.
@@ -577,7 +600,12 @@ when not defined(lwip):
events*: cshort ## The input event flags (see below).
revents*: cshort ## The output event flags (see below).
Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = cint
when defined(zephyr):
type
Tnfds* = distinct cint
else:
type
Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = cint
var
errno* {.importc, header: "<errno.h>".}: cint ## error variable
@@ -625,7 +653,7 @@ elif defined(solaris):
# Solaris doesn't have MSG_NOSIGNAL
const
MSG_NOSIGNAL* = 0'i32
elif defined(freertos) or defined(lwip):
elif defined(zephyr) or defined(freertos) or defined(lwip):
# LwIP/FreeRTOS doesn't have MSG_NOSIGNAL
const
MSG_NOSIGNAL* = 0x20'i32

View File

@@ -462,6 +462,9 @@ var RLIMIT_NOFILE* {.importc: "RLIMIT_NOFILE", header: "<sys/resource.h>".}: cin
# <sys/select.h>
var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "<sys/select.h>".}: cint
when defined(zephyr):
# Zephyr specific hardcoded value
var FD_MAX* {.importc: "CONFIG_POSIX_MAX_FDS ", header: "<sys/select.h>".}: cint
# <sys/socket.h>
var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "<sys/socket.h>".}: cint
@@ -487,10 +490,15 @@ var SO_SNDTIMEO* {.importc: "SO_SNDTIMEO", header: "<sys/socket.h>".}: cint
var SO_TYPE* {.importc: "SO_TYPE", header: "<sys/socket.h>".}: cint
var SOCK_DGRAM* {.importc: "SOCK_DGRAM", header: "<sys/socket.h>".}: cint
var SOCK_RAW* {.importc: "SOCK_RAW", header: "<sys/socket.h>".}: cint
var SOCK_SEQPACKET* {.importc: "SOCK_SEQPACKET", header: "<sys/socket.h>".}: cint
when defined(zephyr):
const SOCK_SEQPACKET* = cint(5)
var SOMAXCONN* {.importc: "CONFIG_NET_SOCKETS_POLL_MAX", header: "<sys/socket.h>".}: cint
else:
var SOCK_SEQPACKET* {.importc: "SOCK_SEQPACKET", header: "<sys/socket.h>".}: cint
var SOMAXCONN* {.importc: "SOMAXCONN", header: "<sys/socket.h>".}: cint
var SOCK_STREAM* {.importc: "SOCK_STREAM", header: "<sys/socket.h>".}: cint
var SOL_SOCKET* {.importc: "SOL_SOCKET", header: "<sys/socket.h>".}: cint
var SOMAXCONN* {.importc: "SOMAXCONN", header: "<sys/socket.h>".}: cint
var MSG_PEEK* {.importc: "MSG_PEEK", header: "<sys/socket.h>".}: cint
var MSG_TRUNC* {.importc: "MSG_TRUNC", header: "<sys/socket.h>".}: cint
var MSG_WAITALL* {.importc: "MSG_WAITALL", header: "<sys/socket.h>".}: cint

View File

@@ -1973,15 +1973,18 @@ proc activeDescriptors*(): int {.inline.} =
when defined(posix):
import posix
when defined(linux) or defined(windows) or defined(macosx) or defined(bsd):
when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or
defined(zephyr) or defined(freertos):
proc maxDescriptors*(): int {.raises: OSError.} =
## Returns the maximum number of active file descriptors for the current
## process. This involves a system call. For now `maxDescriptors` is
## supported on the following OSes: Windows, Linux, OSX, BSD.
when defined(windows):
result = 16_700_000
elif defined(zephyr) or defined(freertos):
result = FD_MAX
else:
var fdLim: RLimit
if getrlimit(RLIMIT_NOFILE, fdLim) < 0:
raiseOSError(osLastError())
result = int(fdLim.rlim_cur) - 1
result = int(fdLim.rlim_cur) - 1

View File

@@ -103,6 +103,7 @@ export SOBool
# TODO: Remove duplication introduced by PR #4683.
const defineSsl = defined(ssl) or defined(nimdoc)
const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr)
when defineSsl:
import openssl
@@ -178,11 +179,12 @@ proc getLocalAddr*(socket: AsyncSocket): (string, Port) =
## This is high-level interface for `getsockname`:idx:.
getLocalAddr(socket.fd, socket.domain)
proc getPeerAddr*(socket: AsyncSocket): (string, Port) =
## Get the socket's peer address and port number.
##
## This is high-level interface for `getpeername`:idx:.
getPeerAddr(socket.fd, socket.domain)
when not useNimNetLite:
proc getPeerAddr*(socket: AsyncSocket): (string, Port) =
## Get the socket's peer address and port number.
##
## This is high-level interface for `getpeername`:idx:.
getPeerAddr(socket.fd, socket.domain)
proc newAsyncSocket*(domain, sockType, protocol: cint,
buffered = true,
@@ -655,7 +657,7 @@ proc hasDataBuffered*(s: AsyncSocket): bool {.since: (1, 5).} =
# xxx dedup with std/net
s.isBuffered and s.bufLen > 0 and s.currPos != s.bufLen
when defined(posix):
when defined(posix) and not useNimNetLite:
proc connectUnix*(socket: AsyncSocket, path: string): owned(Future[void]) =
## Binds Unix socket to `path`.

View File

@@ -73,10 +73,7 @@ type
proc newSelector*[T](): Selector[T] =
# Retrieve the maximum fd count (for current OS) via getrlimit()
var a = RLimit()
if getrlimit(posix.RLIMIT_NOFILE, a) != 0:
raiseOSError(osLastError())
var maxFD = int(a.rlim_max)
var maxFD = maxDescriptors()
doAssert(maxFD > 0)
# Start with a reasonable size, checkFd() will grow this on demand
const numFD = 1024

View File

@@ -53,10 +53,7 @@ else:
body
proc newSelector*[T](): Selector[T] =
var a = RLimit()
if getrlimit(posix.RLIMIT_NOFILE, a) != 0:
raiseIOSelectorsError(osLastError())
var maxFD = int(a.rlim_max)
var maxFD = maxDescriptors()
when hasThreadSupport:
result = cast[Selector[T]](allocShared0(sizeof(SelectorImpl[T])))

View File

@@ -313,7 +313,7 @@ proc selectInto*[T](s: Selector[T], timeout: int,
verifySelectParams(timeout)
if timeout != -1:
when defined(genode) or defined(freertos):
when defined(genode) or defined(freertos) or defined(zephyr):
tv.tv_sec = Time(timeout div 1_000)
else:
tv.tv_sec = timeout.int32 div 1_000

View File

@@ -21,6 +21,7 @@ when hostOS == "solaris":
{.passl: "-lsocket -lnsl".}
const useWinVersion = defined(windows) or defined(nimdoc)
const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr)
when useWinVersion:
import winlean
@@ -35,9 +36,12 @@ else:
export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
Sockaddr_in6, Sockaddr_storage,
inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto,
recv, `==`, connect, send, accept, recvfrom, sendto,
freeAddrInfo
when not useNimNetLite:
export inet_ntoa
export
SO_ERROR,
SOL_SOCKET,
@@ -332,125 +336,6 @@ template htons*(x: uint16): untyped =
## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
nativesockets.ntohs(x)
proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
## Searches the database from the beginning and finds the first entry for
## which the service name specified by `name` matches the s_name member
## and the protocol name specified by `proto` matches the s_proto member.
##
## On posix this will search through the `/etc/services` file.
when useWinVersion:
var s = winlean.getservbyname(name, proto)
else:
var s = posix.getservbyname(name, proto)
if s == nil: raiseOSError(osLastError(), "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = Port(s.s_port)
result.proto = $s.s_proto
proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} =
## Searches the database from the beginning and finds the first entry for
## which the port specified by `port` matches the s_port member and the
## protocol name specified by `proto` matches the s_proto member.
##
## On posix this will search through the `/etc/services` file.
when useWinVersion:
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
else:
var s = posix.getservbyport(ze(int16(port)).cint, proto)
if s == nil: raiseOSError(osLastError(), "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = Port(s.s_port)
result.proto = $s.s_proto
proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
## This function will lookup the hostname of an IP Address.
var myaddr: InAddr
myaddr.s_addr = inet_addr(ip)
when useWinVersion:
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
cint(AF_INET))
if s == nil: raiseOSError(osLastError())
else:
var s =
when defined(android4):
posix.gethostbyaddr(cast[cstring](addr(myaddr)), sizeof(myaddr).cint,
cint(posix.AF_INET))
else:
posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).SockLen,
cint(posix.AF_INET))
if s == nil:
raiseOSError(osLastError(), $hstrerror(h_errno))
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when useWinVersion:
result.addrtype = Domain(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:
raiseOSError(osLastError(), "unknown h_addrtype")
if result.addrtype == AF_INET:
result.addrList = @[]
var i = 0
while not isNil(s.h_addr_list[i]):
var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i])
result.addrList.add($inet_ntoa(inaddrPtr[]))
inc(i)
else:
result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length)
proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
## This function will lookup the IP address of a hostname.
when useWinVersion:
var s = winlean.gethostbyname(name)
else:
var s = posix.gethostbyname(name)
if s == nil: raiseOSError(osLastError())
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when useWinVersion:
result.addrtype = Domain(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:
raiseOSError(osLastError(), "unknown h_addrtype")
if result.addrtype == AF_INET:
result.addrList = @[]
var i = 0
while not isNil(s.h_addr_list[i]):
var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i])
result.addrList.add($inet_ntoa(inaddrPtr[]))
inc(i)
else:
result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length)
proc getHostname*(): string {.tags: [ReadIOEffect].} =
## Returns the local hostname (not the FQDN)
# https://tools.ietf.org/html/rfc1035#section-2.3.1
# https://tools.ietf.org/html/rfc2181#section-11
const size = 256
result = newString(size)
when useWinVersion:
let success = winlean.gethostname(result, size)
else:
# Posix
let success = posix.gethostname(result, size)
if success != 0.cint:
raiseOSError(osLastError())
let x = len(cstring(result))
result.setLen(x)
proc getSockDomain*(socket: SocketHandle): Domain =
## Returns the socket's domain (AF_INET or AF_INET6).
var name: Sockaddr_in6
@@ -464,162 +349,354 @@ proc getSockDomain*(socket: SocketHandle): Domain =
else:
raise newException(IOError, "Unknown socket family in getSockDomain")
proc getAddrString*(sockAddr: ptr SockAddr): string =
## Returns the string representation of address within sockAddr
if sockAddr.sa_family.cint == nativeAfInet:
result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr)
elif sockAddr.sa_family.cint == nativeAfInet6:
let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN.int
else: 46 # it's actually 46 in both cases
result = newString(addrLen)
let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr
when not useWinVersion:
if posix.inet_ntop(posix.AF_INET6, addr6, addr result[0],
result.len.int32) == nil:
raiseOSError(osLastError())
if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0:
result.setSlice("::ffff:".len..<addrLen)
when not useNimNetLite:
proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
## Searches the database from the beginning and finds the first entry for
## which the service name specified by `name` matches the s_name member
## and the protocol name specified by `proto` matches the s_proto member.
##
## On posix this will search through the `/etc/services` file.
when useWinVersion:
var s = winlean.getservbyname(name, proto)
else:
if winlean.inet_ntop(winlean.AF_INET6, addr6, addr result[0],
result.len.int32) == nil:
raiseOSError(osLastError())
setLen(result, len(cstring(result)))
else:
when defined(posix) and not defined(nimdoc):
if sockAddr.sa_family.cint == nativeAfUnix:
return "unix"
raise newException(IOError, "Unknown socket family in getAddrString")
var s = posix.getservbyname(name, proto)
if s == nil: raiseOSError(osLastError(), "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = Port(s.s_port)
result.proto = $s.s_proto
proc getAddrString*(sockAddr: ptr SockAddr, strAddress: var string) =
## Stores in `strAddress` the string representation of the address inside
## `sockAddr`
##
## **Note**
## * `strAddress` must be initialized to 46 in length.
const length = 46
assert(length == len(strAddress),
"`strAddress` was not initialized correctly. 46 != `len(strAddress)`")
if sockAddr.sa_family.cint == nativeAfInet:
let addr4 = addr cast[ptr Sockaddr_in](sockAddr).sin_addr
when not useWinVersion:
if posix.inet_ntop(posix.AF_INET, addr4, addr strAddress[0],
strAddress.len.int32) == nil:
raiseOSError(osLastError())
proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} =
## Searches the database from the beginning and finds the first entry for
## which the port specified by `port` matches the s_port member and the
## protocol name specified by `proto` matches the s_proto member.
##
## On posix this will search through the `/etc/services` file.
when useWinVersion:
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
else:
if winlean.inet_ntop(winlean.AF_INET, addr4, addr strAddress[0],
strAddress.len.int32) == nil:
raiseOSError(osLastError())
elif sockAddr.sa_family.cint == nativeAfInet6:
let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr
when not useWinVersion:
if posix.inet_ntop(posix.AF_INET6, addr6, addr strAddress[0],
strAddress.len.int32) == nil:
raiseOSError(osLastError())
if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0:
strAddress.setSlice("::ffff:".len..<length)
var s = posix.getservbyport(ze(int16(port)).cint, proto)
if s == nil: raiseOSError(osLastError(), "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = Port(s.s_port)
result.proto = $s.s_proto
proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
## This function will lookup the hostname of an IP Address.
var myaddr: InAddr
myaddr.s_addr = inet_addr(ip)
when useWinVersion:
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
cint(AF_INET))
if s == nil: raiseOSError(osLastError())
else:
if winlean.inet_ntop(winlean.AF_INET6, addr6, addr strAddress[0],
strAddress.len.int32) == nil:
var s =
when defined(android4):
posix.gethostbyaddr(cast[cstring](addr(myaddr)), sizeof(myaddr).cint,
cint(posix.AF_INET))
else:
posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).SockLen,
cint(posix.AF_INET))
if s == nil:
raiseOSError(osLastError(), $hstrerror(h_errno))
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when useWinVersion:
result.addrtype = Domain(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:
raiseOSError(osLastError(), "unknown h_addrtype")
if result.addrtype == AF_INET:
result.addrList = @[]
var i = 0
while not isNil(s.h_addr_list[i]):
var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i])
result.addrList.add($inet_ntoa(inaddrPtr[]))
inc(i)
else:
result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length)
proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
## This function will lookup the IP address of a hostname.
when useWinVersion:
var s = winlean.gethostbyname(name)
else:
var s = posix.gethostbyname(name)
if s == nil: raiseOSError(osLastError())
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when useWinVersion:
result.addrtype = Domain(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:
raiseOSError(osLastError(), "unknown h_addrtype")
if result.addrtype == AF_INET:
result.addrList = @[]
var i = 0
while not isNil(s.h_addr_list[i]):
var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i])
result.addrList.add($inet_ntoa(inaddrPtr[]))
inc(i)
else:
result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length)
proc getHostname*(): string {.tags: [ReadIOEffect].} =
## Returns the local hostname (not the FQDN)
# https://tools.ietf.org/html/rfc1035#section-2.3.1
# https://tools.ietf.org/html/rfc2181#section-11
const size = 256
result = newString(size)
when useWinVersion:
let success = winlean.gethostname(result, size)
else:
# Posix
let success = posix.gethostname(result, size)
if success != 0.cint:
raiseOSError(osLastError())
let x = len(cstring(result))
result.setLen(x)
proc getAddrString*(sockAddr: ptr SockAddr): string =
## Returns the string representation of address within sockAddr
if sockAddr.sa_family.cint == nativeAfInet:
result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr)
elif sockAddr.sa_family.cint == nativeAfInet6:
let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN.int
else: 46 # it's actually 46 in both cases
result = newString(addrLen)
let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr
when not useWinVersion:
if posix.inet_ntop(posix.AF_INET6, addr6, addr result[0],
result.len.int32) == nil:
raiseOSError(osLastError())
if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0:
result.setSlice("::ffff:".len..<addrLen)
else:
if winlean.inet_ntop(winlean.AF_INET6, addr6, addr result[0],
result.len.int32) == nil:
raiseOSError(osLastError())
setLen(result, len(cstring(result)))
else:
when defined(posix) and not defined(nimdoc):
if sockAddr.sa_family.cint == nativeAfUnix:
return "unix"
raise newException(IOError, "Unknown socket family in getAddrString")
proc getAddrString*(sockAddr: ptr SockAddr, strAddress: var string) =
## Stores in `strAddress` the string representation of the address inside
## `sockAddr`
##
## **Note**
## * `strAddress` must be initialized to 46 in length.
const length = 46
assert(length == len(strAddress),
"`strAddress` was not initialized correctly. 46 != `len(strAddress)`")
if sockAddr.sa_family.cint == nativeAfInet:
let addr4 = addr cast[ptr Sockaddr_in](sockAddr).sin_addr
when not useWinVersion:
if posix.inet_ntop(posix.AF_INET, addr4, addr strAddress[0],
strAddress.len.int32) == nil:
raiseOSError(osLastError())
else:
if winlean.inet_ntop(winlean.AF_INET, addr4, addr strAddress[0],
strAddress.len.int32) == nil:
raiseOSError(osLastError())
elif sockAddr.sa_family.cint == nativeAfInet6:
let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr
when not useWinVersion:
if posix.inet_ntop(posix.AF_INET6, addr6, addr strAddress[0],
strAddress.len.int32) == nil:
raiseOSError(osLastError())
if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0:
strAddress.setSlice("::ffff:".len..<length)
else:
if winlean.inet_ntop(winlean.AF_INET6, addr6, addr strAddress[0],
strAddress.len.int32) == nil:
raiseOSError(osLastError())
else:
raise newException(IOError, "Unknown socket family in getAddrString")
setLen(strAddress, len(cstring(strAddress)))
when defined(posix) and not defined(nimdoc):
proc makeUnixAddr*(path: string): Sockaddr_un =
result.sun_family = AF_UNIX.TSa_Family
if path.len >= Sockaddr_un_path_length:
raise newException(ValueError, "socket path too long")
copyMem(addr result.sun_path, path.cstring, path.len + 1)
proc getSockName*(socket: SocketHandle): Port =
## Returns the socket's associated port number.
var name: Sockaddr_in
when useWinVersion:
name.sin_family = uint16(ord(AF_INET))
else:
name.sin_family = TSa_Family(posix.AF_INET)
#name.sin_port = htons(cint16(port))
#name.sin_addr.s_addr = htonl(INADDR_ANY)
var namelen = sizeof(name).SockLen
if getsockname(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
result = Port(nativesockets.ntohs(name.sin_port))
proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
## Returns the socket's local address and port number.
##
## Similar to POSIX's `getsockname`:idx:.
case domain
of AF_INET:
var name: Sockaddr_in
when useWinVersion:
name.sin_family = uint16(ord(AF_INET))
else:
name.sin_family = TSa_Family(posix.AF_INET)
var namelen = sizeof(name).SockLen
if getsockname(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
else:
raise newException(IOError, "Unknown socket family in getAddrString")
setLen(strAddress, len(cstring(strAddress)))
result = ($inet_ntoa(name.sin_addr),
Port(nativesockets.ntohs(name.sin_port)))
of AF_INET6:
var name: Sockaddr_in6
when useWinVersion:
name.sin6_family = uint16(ord(AF_INET6))
else:
name.sin6_family = TSa_Family(posix.AF_INET6)
var namelen = sizeof(name).SockLen
if getsockname(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
# Cannot use INET6_ADDRSTRLEN here, because it's a C define.
result[0] = newString(64)
if inet_ntop(name.sin6_family.cint,
addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
raiseOSError(osLastError())
setLen(result[0], result[0].cstring.len)
result[1] = Port(nativesockets.ntohs(name.sin6_port))
else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
when defined(posix) and not defined(nimdoc):
proc makeUnixAddr*(path: string): Sockaddr_un =
result.sun_family = AF_UNIX.TSa_Family
if path.len >= Sockaddr_un_path_length:
raise newException(ValueError, "socket path too long")
copyMem(addr result.sun_path, path.cstring, path.len + 1)
proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
## Returns the socket's peer address and port number.
##
## Similar to POSIX's `getpeername`:idx:
case domain
of AF_INET:
var name: Sockaddr_in
when useWinVersion:
name.sin_family = uint16(ord(AF_INET))
else:
name.sin_family = TSa_Family(posix.AF_INET)
var namelen = sizeof(name).SockLen
if getpeername(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
result = ($inet_ntoa(name.sin_addr),
Port(nativesockets.ntohs(name.sin_port)))
of AF_INET6:
var name: Sockaddr_in6
when useWinVersion:
name.sin6_family = uint16(ord(AF_INET6))
else:
name.sin6_family = TSa_Family(posix.AF_INET6)
var namelen = sizeof(name).SockLen
if getpeername(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
# Cannot use INET6_ADDRSTRLEN here, because it's a C define.
result[0] = newString(64)
if inet_ntop(name.sin6_family.cint,
addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
raiseOSError(osLastError())
setLen(result[0], result[0].cstring.len)
result[1] = Port(nativesockets.ntohs(name.sin6_port))
else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
when useNimNetLite:
proc getSockName*(socket: SocketHandle): Port =
## Returns the socket's associated port number.
var name: Sockaddr_in
when useWinVersion:
name.sin_family = uint16(ord(AF_INET))
else:
name.sin_family = TSa_Family(posix.AF_INET)
#name.sin_port = htons(cint16(port))
#name.sin_addr.s_addr = htonl(INADDR_ANY)
var namelen = sizeof(name).SockLen
if getsockname(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
result = Port(nativesockets.ntohs(name.sin_port))
const
INET_ADDRSTRLEN = 16
INET6_ADDRSTRLEN = 46 # it's actually 46 in both cases
proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
## Returns the socket's local address and port number.
##
## Similar to POSIX's `getsockname`:idx:.
case domain
of AF_INET:
var name: Sockaddr_in
when useWinVersion:
name.sin_family = uint16(ord(AF_INET))
else:
name.sin_family = TSa_Family(posix.AF_INET)
var namelen = sizeof(name).SockLen
if getsockname(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
result = ($inet_ntoa(name.sin_addr),
Port(nativesockets.ntohs(name.sin_port)))
of AF_INET6:
var name: Sockaddr_in6
when useWinVersion:
name.sin6_family = uint16(ord(AF_INET6))
else:
name.sin6_family = TSa_Family(posix.AF_INET6)
var namelen = sizeof(name).SockLen
if getsockname(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
# Cannot use INET6_ADDRSTRLEN here, because it's a C define.
result[0] = newString(64)
if inet_ntop(name.sin6_family.cint,
addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
raiseOSError(osLastError())
setLen(result[0], result[0].cstring.len)
result[1] = Port(nativesockets.ntohs(name.sin6_port))
else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
proc sockAddrToStr(sa: ptr Sockaddr): string {.noinit.} =
let af_family = sa.sa_family
var nl, v4Slice: cint
var si_addr: ptr InAddr
proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
## Returns the socket's peer address and port number.
##
## Similar to POSIX's `getpeername`:idx:
case domain
of AF_INET:
var name: Sockaddr_in
when useWinVersion:
name.sin_family = uint16(ord(AF_INET))
if af_family == AF_INET.TSa_Family:
nl = INET_ADDRSTRLEN
si_addr = cast[ptr Sockaddr_in](sa).sin_addr.addr()
elif af_family == AF_INET6.TSa_Family:
nl = INET6_ADDRSTRLEN
let si6_addr = cast[ptr Sockaddr_in6](sa).sin6_addr.addr()
si_addr = cast[ptr InAddr](si6_addr) # let's us reuse logic below
when defined(posix) and not defined(nimdoc) and not defined(zephyr):
if posix.IN6_IS_ADDR_V4MAPPED(si6_addr) != 0:
v4Slice = "::ffff:".len()
else:
name.sin_family = TSa_Family(posix.AF_INET)
var namelen = sizeof(name).SockLen
if getpeername(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
result = ($inet_ntoa(name.sin_addr),
Port(nativesockets.ntohs(name.sin_port)))
of AF_INET6:
var name: Sockaddr_in6
when useWinVersion:
name.sin6_family = uint16(ord(AF_INET6))
when defined(posix) and not defined(nimdoc):
if af_family.cint == nativeAfUnix:
return "unix"
return ""
result = newString(nl)
let namePtr = result.cstring()
if namePtr == inet_ntop(af_family.cint, si_addr, namePtr, nl):
result.setLen(len(namePtr))
if v4Slice > 0: result.setSlice(v4Slice.int ..< nl.int)
else:
name.sin6_family = TSa_Family(posix.AF_INET6)
var namelen = sizeof(name).SockLen
if getpeername(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
return ""
proc sockAddrToStr(sa: var Sockaddr_in | var Sockaddr_in6): string =
result = sockAddrToStr(cast[ptr SockAddr](unsafeAddr(sa)))
proc getAddrString*(sockAddr: ptr SockAddr): string =
result = sockAddrToStr(sockAddr)
if result.len() == 0:
raiseOSError(osLastError())
# Cannot use INET6_ADDRSTRLEN here, because it's a C define.
result[0] = newString(64)
if inet_ntop(name.sin6_family.cint,
addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
raiseOSError(osLastError())
setLen(result[0], result[0].cstring.len)
result[1] = Port(nativesockets.ntohs(name.sin6_port))
else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
proc getAddrString*(sockAddr: ptr SockAddr, strAddress: var string) {.noinit.} =
strAddress = getAddrString(sockAddr)
proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
## Returns the socket's local address and port number.
##
## Similar to POSIX's `getsockname`:idx:.
template sockGetNameOrRaiseError(socket: untyped, name: untyped) =
var namelen = sizeof(socket).SockLen
if getsockname(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
case domain
of AF_INET:
var name = Sockaddr_in(sin_family: TSa_Family(posix.AF_INET))
sockGetNameOrRaiseError(socket, name)
result = (sockAddrToStr(name),
Port(nativesockets.ntohs(name.sin_port)))
of AF_INET6:
var name = Sockaddr_in6(sin6_family: TSa_Family(posix.AF_INET6))
sockGetNameOrRaiseError(socket, name)
result = (sockAddrToStr(name),
Port(nativesockets.ntohs(name.sin6_port)))
else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {.
tags: [ReadIOEffect].} =
@@ -733,14 +810,14 @@ proc accept*(fd: SocketHandle, inheritable = defined(nimInheritHandles)): (Socke
## child processes.
##
## Returns (osInvalidSocket, "") if an error occurred.
var sockAddress: Sockaddr_in
var sockAddress: Sockaddr
var addrLen = sizeof(sockAddress).SockLen
var sock =
when (defined(linux) or defined(bsd)) and not defined(nimdoc):
accept4(fd, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen),
accept4(fd, addr(sockAddress), addr(addrLen),
if inheritable: 0 else: SOCK_CLOEXEC)
else:
accept(fd, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
accept(fd, addr(sockAddress), addr(addrLen))
when declared(setInheritable) and not (defined(linux) or defined(bsd)):
if not setInheritable(sock, inheritable):
close sock
@@ -748,7 +825,11 @@ proc accept*(fd: SocketHandle, inheritable = defined(nimInheritHandles)): (Socke
if sock == osInvalidSocket:
return (osInvalidSocket, "")
else:
return (sock, $inet_ntoa(sockAddress.sin_addr))
when useNimNetLite:
var name = sockAddrToStr(addr sockAddress)
return (sock, name)
else:
return (sock, $inet_ntoa(cast[Sockaddr_in](sockAddress).sin_addr))
when defined(windows):
var wsa: WSAData

View File

@@ -85,12 +85,14 @@ runnableExamples("-r:off"):
import std/private/since
import nativesockets, os, strutils, times, sets, options, std/monotimes
import nativesockets
import os, strutils, times, sets, options, std/monotimes
import ssl_config
export nativesockets.Port, nativesockets.`$`, nativesockets.`==`
export Domain, SockType, Protocol
const useWinVersion = defined(windows) or defined(nimdoc)
const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr)
const defineSsl = defined(ssl) or defined(nimdoc)
when useWinVersion:
@@ -1243,11 +1245,12 @@ proc getLocalAddr*(socket: Socket): (string, Port) =
## This is high-level interface for `getsockname`:idx:.
getLocalAddr(socket.fd, socket.domain)
proc getPeerAddr*(socket: Socket): (string, Port) =
## Get the socket's peer address and port number.
##
## This is high-level interface for `getpeername`:idx:.
getPeerAddr(socket.fd, socket.domain)
when not useNimNetLite:
proc getPeerAddr*(socket: Socket): (string, Port) =
## Get the socket's peer address and port number.
##
## This is high-level interface for `getpeername`:idx:.
getPeerAddr(socket.fd, socket.domain)
proc setSockOpt*(socket: Socket, opt: SOBool, value: bool,
level = SOL_SOCKET) {.tags: [WriteIOEffect].} =
@@ -1259,7 +1262,7 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool,
var valuei = cint(if value: 1 else: 0)
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
when defined(posix) or defined(nimdoc):
when defined(nimdoc) or (defined(posix) and not useNimNetLite):
proc connectUnix*(socket: Socket, path: string) =
## Connects to Unix socket on `path`.
## This only works on Unix-style systems: Mac OS X, BSD and Linux

View File

@@ -323,6 +323,23 @@ else:
# Anything higher is the time to wait in milliseconds.
doAssert(timeout >= -1, "Cannot select with a negative value, got: " & $timeout)
when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or
defined(zephyr) or defined(freertos):
template maxDescriptors*(): int =
## Returns the maximum number of active file descriptors for the current
## process. This involves a system call. For now `maxDescriptors` is
## supported on the following OSes: Windows, Linux, OSX, BSD.
when defined(windows):
16_700_000
elif defined(zephyr) or defined(freertos):
FD_MAX
else:
var fdLim: RLimit
var res = int(getrlimit(RLIMIT_NOFILE, fdLim))
if res >= 0:
res = int(fdLim.rlim_cur) - 1
res
when defined(linux) and not defined(emscripten):
include ioselects/ioselectors_epoll
elif bsdPlatform:
@@ -337,5 +354,7 @@ else:
include ioselects/ioselectors_select
elif defined(freertos) or defined(lwip):
include ioselects/ioselectors_select
elif defined(zephyr):
include ioselects/ioselectors_poll
else:
include ioselects/ioselectors_poll

View File

@@ -174,14 +174,29 @@ proc c_sprintf*(buf, frmt: cstring): cint {.
importc: "sprintf", header: "<stdio.h>", varargs, noSideEffect.}
# we use it only in a way that cannot lead to security issues
proc c_malloc*(size: csize_t): pointer {.
importc: "malloc", header: "<stdlib.h>".}
proc c_calloc*(nmemb, size: csize_t): pointer {.
importc: "calloc", header: "<stdlib.h>".}
proc c_free*(p: pointer) {.
importc: "free", header: "<stdlib.h>".}
proc c_realloc*(p: pointer, newsize: csize_t): pointer {.
importc: "realloc", header: "<stdlib.h>".}
when defined(zephyr) and not defined(zephyrUseLibcMalloc):
proc c_malloc*(size: csize_t): pointer {.
importc: "k_malloc", header: "<kernel.h>".}
proc c_calloc*(nmemb, size: csize_t): pointer {.
importc: "k_calloc", header: "<kernel.h>".}
proc c_free*(p: pointer) {.
importc: "k_free", header: "<kernel.h>".}
proc c_realloc*(p: pointer, newsize: csize_t): pointer =
# Zephyr's kernel malloc doesn't support realloc
result = c_malloc(newSize)
# match the ansi c behavior
if not result.isNil():
copyMem(result, p, newSize)
c_free(p)
else:
proc c_malloc*(size: csize_t): pointer {.
importc: "malloc", header: "<stdlib.h>".}
proc c_calloc*(nmemb, size: csize_t): pointer {.
importc: "calloc", header: "<stdlib.h>".}
proc c_free*(p: pointer) {.
importc: "free", header: "<stdlib.h>".}
proc c_realloc*(p: pointer, newsize: csize_t): pointer {.
importc: "realloc", header: "<stdlib.h>".}
proc c_fwrite*(buf: pointer, size, n: csize_t, f: CFilePtr): cint {.
importc: "fwrite", header: "<stdio.h>".}

View File

@@ -15,6 +15,7 @@ const
PageSize = 1 shl PageShift
PageMask = PageSize-1
MemAlign = # also minimal allocatable memory block
when defined(useMalloc):
when defined(amd64): 16

View File

@@ -176,7 +176,7 @@ elif defined(genode):
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
raiseAssert("nimGetProcAddr not implemented")
elif defined(nintendoswitch) or defined(freertos):
elif defined(nintendoswitch) or defined(freertos) or defined(zephyr):
proc nimUnloadLibrary(lib: LibHandle) =
cstderr.rawWrite("nimUnLoadLibrary not implemented")
cstderr.rawWrite("\n")

View File

@@ -361,7 +361,7 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w
## availability with `declared() <system.html#declared,untyped>`.
when SupportIoctlInheritCtl:
result = c_ioctl(f, if inheritable: FIONCLEX else: FIOCLEX) != -1
elif defined(freertos):
elif defined(freertos) or defined(zephyr):
result = true
elif defined(posix):
var flags = c_fcntl(f, F_GETFD)
@@ -794,8 +794,11 @@ when declared(stdout):
var echoLock: SysLock
initSysLock echoLock
const stdOutLock = not defined(windows) and not defined(android) and
not defined(nintendoswitch) and not defined(freertos) and
const stdOutLock = not defined(windows) and
not defined(android) and
not defined(nintendoswitch) and
not defined(freertos) and
not defined(zephyr) and
hostOS != "any"
proc echoBinSafe(args: openArray[string]) {.compilerproc.} =

View File

@@ -2,13 +2,22 @@
{.push stackTrace: off.}
proc allocImpl(size: Natural): pointer =
c_malloc(size.csize_t)
result = c_malloc(size.csize_t)
when defined(zephyr):
if result == nil:
raiseOutOfMem()
proc alloc0Impl(size: Natural): pointer =
c_calloc(size.csize_t, 1)
result = c_calloc(size.csize_t, 1)
when defined(zephyr):
if result == nil:
raiseOutOfMem()
proc reallocImpl(p: pointer, newSize: Natural): pointer =
c_realloc(p, newSize.csize_t)
result = c_realloc(p, newSize.csize_t)
when defined(zephyr):
if result == nil:
raiseOutOfMem()
proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer =
result = realloc(p, newSize.csize_t)

View File

@@ -1,6 +1,6 @@
discard """
targets: "c"
cmd: "nim $target --os:freertos --gc:arc $options $file"
cmd: "nim $target --compileOnly --os:freertos --gc:arc $options $file"
disabled: "bsd"
disabled: "windows"
action: compile