diff options
author | Jaremy Creechley <creechley@gmail.com> | 2021-10-24 09:51:57 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-24 11:51:57 +0200 |
commit | 141b76e36519219915ada9086d1c9b1d0b465659 (patch) | |
tree | 1407e59588def9ba684bd7e5b3372a66a02b0961 /lib | |
parent | 41d99185918923063bd6ae34898c8ac18a941169 (diff) | |
download | Nim-141b76e36519219915ada9086d1c9b1d0b465659.tar.gz |
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>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/posix/posix.nim | 6 | ||||
-rw-r--r-- | lib/posix/posix_freertos_consts.nim | 2 | ||||
-rw-r--r-- | lib/posix/posix_other.nim | 94 | ||||
-rw-r--r-- | lib/posix/posix_other_consts.nim | 12 | ||||
-rw-r--r-- | lib/pure/asyncdispatch.nim | 7 | ||||
-rw-r--r-- | lib/pure/asyncnet.nim | 14 | ||||
-rw-r--r-- | lib/pure/ioselects/ioselectors_epoll.nim | 5 | ||||
-rw-r--r-- | lib/pure/ioselects/ioselectors_poll.nim | 5 | ||||
-rw-r--r-- | lib/pure/ioselects/ioselectors_select.nim | 2 | ||||
-rw-r--r-- | lib/pure/nativesockets.nim | 605 | ||||
-rw-r--r-- | lib/pure/net.nim | 17 | ||||
-rw-r--r-- | lib/pure/selectors.nim | 19 | ||||
-rw-r--r-- | lib/system/ansi_c.nim | 31 | ||||
-rw-r--r-- | lib/system/bitmasks.nim | 1 | ||||
-rw-r--r-- | lib/system/dyncalls.nim | 2 | ||||
-rw-r--r-- | lib/system/io.nim | 9 | ||||
-rw-r--r-- | lib/system/mm/malloc.nim | 15 |
17 files changed, 508 insertions, 338 deletions
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 45fe00d5d..c2504f994 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -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 {. diff --git a/lib/posix/posix_freertos_consts.nim b/lib/posix/posix_freertos_consts.nim index efe87aacf..ca500534a 100644 --- a/lib/posix/posix_freertos_consts.nim +++ b/lib/posix/posix_freertos_consts.nim @@ -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 diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 6584bfab2..688867b98 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -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,49 +428,51 @@ 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). -else: + 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. - sa_data*: array[0..255, char] ## Socket address (variable-length data). + data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data). -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 - - -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. + 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..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-sizeof(TSa_Family), char] ## Socket path + + +type Tif_nameindex* {.importc: "struct if_nameindex", final, pure, header: "<net/if.h>".} = object ## struct if_nameindex if_index*: cint ## Numeric index of the interface. @@ -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 diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index f43407b40..59ac6f9ed 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -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 diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index d87e2360f..e15fb0851 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -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 \ No newline at end of file diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 5523fa10e..abb4dd075 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -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`. diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index b62b4c2db..05d9d19a8 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -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 diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 6b10e19ae..0d8fef78a 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -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]))) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 6f216ac85..88cbaf28c 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -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 diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 13c08dd92..4037d7181 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -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") - -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()) + 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: - 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: - 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)) + 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 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 + proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = + ## This function will lookup the IP address of a hostname. when useWinVersion: - name.sin_family = uint16(ord(AF_INET)) + var s = winlean.gethostbyname(name) 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 + var s = posix.gethostbyname(name) + if s == nil: raiseOSError(osLastError()) + result.name = $s.h_name + result.aliases = cstringArrayToSeq(s.h_aliases) when useWinVersion: - name.sin6_family = uint16(ord(AF_INET6)) + result.addrtype = Domain(s.h_addrtype) 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: + 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()) - 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 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: + 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 getpeername(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: + 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)) + 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()) + 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: - 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(OSErrorCode(-1), "invalid socket family in getLocalAddr") + + 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: + + when useWinVersion: + const + INET_ADDRSTRLEN = 16 + INET6_ADDRSTRLEN = 46 # it's actually 46 in both cases + + proc sockAddrToStr(sa: ptr Sockaddr): string {.noinit.} = + let af_family = sa.sa_family + var nl, v4Slice: cint + var si_addr: ptr InAddr + + 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: + 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: + 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()) - 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 diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 09cdc8afb..7b0ff78e7 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -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 diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 82550e09b..ec441f6da 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -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 diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index e5f26e070..259d36633 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -142,14 +142,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>".} diff --git a/lib/system/bitmasks.nim b/lib/system/bitmasks.nim index d7c55a4d9..caf86568a 100644 --- a/lib/system/bitmasks.nim +++ b/lib/system/bitmasks.nim @@ -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 diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index c14fcf31e..36c2c5fe1 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -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") diff --git a/lib/system/io.nim b/lib/system/io.nim index 59f070f73..6f4accc2a 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -347,7 +347,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) @@ -780,8 +780,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.} = diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index 2ba5c0fec..d41dce705 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -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) |