diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 57dd6e2c7e..5dea7dd22e 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -155,10 +155,16 @@ when not defined(zephyr): proc inet_addr*(a1: cstring): InAddrT {.importc, header: "".} proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "".} -proc inet_ntop*(a1: cint, a2: pointer | ptr InAddr | ptr In6Addr, a3: cstring, a4: int32): cstring {. - importc:"(char *)$1", header: "".} -proc inet_pton*(a1: cint, a2: cstring, a3: pointer | ptr InAddr | ptr In6Addr): cint {. - importc, header: "".} +when defined(zephyr): # this switch is done to keep Nim 1.6 API backward compatible + proc inet_ntop*(a1: cint, a2: pointer | ptr InAddr | ptr In6Addr, a3: cstring, a4: int32): cstring {. + importc:"(char *)$1", header: "".} + proc inet_pton*(a1: cint, a2: cstring, a3: pointer | ptr InAddr | ptr In6Addr): cint {. + importc, header: "".} +else: + proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {. + importc:"(char *)$1", header: "".} + proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {. + importc, header: "".} var in6addr_any* {.importc, header: "".}: In6Addr diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 9778856e25..f25fc142b5 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -65,10 +65,11 @@ runnableExamples("-r:off"): let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) socket.sendTo("192.168.0.1", Port(27960), "status\n") -runnableExamples("-r:off"): - let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) - let ip = parseIpAddress("192.168.0.1") - doAssert socket.sendTo(ip, Port(27960), "status\c\l") == 8 +when defined(zephyr): + runnableExamples("-r:off"): + let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) + let ip = parseIpAddress("192.168.0.1") + doAssert socket.sendTo(ip, Port(27960), "status\c\l") == 8 ## Creating a server ## ----------------- @@ -1612,53 +1613,98 @@ proc recvLine*(socket: Socket, timeout = -1, result = "" readLine(socket, result, timeout, flags, maxLength) -proc recvFrom*[T: string | IpAddress](socket: Socket, data: var string, length: int, - address: var T, port: var Port, flags = 0'i32): int {. - tags: [ReadIOEffect].} = - ## Receives data from `socket`. This function should normally be used with - ## connection-less sockets (UDP sockets). The source address of the data - ## packet is stored in the `address` argument as either a string or an IpAddress. - ## - ## If an error occurs an OSError exception will be raised. Otherwise the return - ## value will be the length of data received. - ## - ## .. warning:: This function does not yet have a buffered implementation, - ## so when `socket` is buffered the non-buffered implementation will be - ## used. Therefore if `socket` contains something in its buffer this - ## function will make no effort to return it. - template adaptRecvFromToDomain(sockAddress: untyped, domain: Domain) = - var addrLen = sizeof(sockAddress).SockLen - result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, - cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) - if result != -1: - data.setLen(result) +when defined(zephyr): # this switch is done to keep Nim 1.6 API backward compatible + proc recvFrom*[T: string | IpAddress](socket: Socket, data: var string, length: int, + address: var T, port: var Port, flags = 0'i32): int {. + tags: [ReadIOEffect].} = + ## Receives data from `socket`. This function should normally be used with + ## connection-less sockets (UDP sockets). The source address of the data + ## packet is stored in the `address` argument as either a string or an IpAddress. + ## + ## If an error occurs an OSError exception will be raised. Otherwise the return + ## value will be the length of data received. + ## + ## .. warning:: This function does not yet have a buffered implementation, + ## so when `socket` is buffered the non-buffered implementation will be + ## used. Therefore if `socket` contains something in its buffer this + ## function will make no effort to return it. + template adaptRecvFromToDomain(sockAddress: untyped, domain: Domain) = + var addrLen = sizeof(sockAddress).SockLen + result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, + cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) - when typeof(address) is string: + if result != -1: + data.setLen(result) + + when typeof(address) is string: + address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) + when domain == AF_INET6: + port = ntohs(sockAddress.sin6_port).Port + else: + port = ntohs(sockAddress.sin_port).Port + else: + data.setLen(result) + sockAddress.fromSockAddr(addrLen, address, port) + else: + raiseOSError(osLastError()) + + assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket") + # TODO: Buffered sockets + data.setLen(length) + + case socket.domain + of AF_INET6: + var sockAddress: Sockaddr_in6 + adaptRecvFromToDomain(sockAddress, AF_INET6) + of AF_INET: + var sockAddress: Sockaddr_in + adaptRecvFromToDomain(sockAddress, AF_INET) + else: + raise newException(ValueError, "Unknown socket address family") + +else: + proc recvFrom*(socket: Socket, data: var string, length: int, + address: var string, port: var Port, flags = 0'i32): int {. + tags: [ReadIOEffect].} = + ## Receives data from `socket`. This function should normally be used with + ## connection-less sockets (UDP sockets). + ## + ## If an error occurs an OSError exception will be raised. Otherwise the return + ## value will be the length of data received. + ## + ## .. warning:: This function does not yet have a buffered implementation, + ## so when `socket` is buffered the non-buffered implementation will be + ## used. Therefore if `socket` contains something in its buffer this + ## function will make no effort to return it. + template adaptRecvFromToDomain(domain: Domain) = + var addrLen = SockLen(sizeof(sockAddress)) + result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, + cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) + + if result != -1: + data.setLen(result) address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) when domain == AF_INET6: port = ntohs(sockAddress.sin6_port).Port else: port = ntohs(sockAddress.sin_port).Port else: - data.setLen(result) - sockAddress.fromSockAddr(addrLen, address, port) + raiseOSError(osLastError()) + + assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket") + # TODO: Buffered sockets + data.setLen(length) + case socket.domain + of AF_INET6: + var sockAddress: Sockaddr_in6 + adaptRecvFromToDomain(AF_INET6) + of AF_INET: + var sockAddress: Sockaddr_in + adaptRecvFromToDomain(AF_INET) else: - raiseOSError(osLastError()) + raise newException(ValueError, "Unknown socket address family") - assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket") - # TODO: Buffered sockets - data.setLen(length) - - case socket.domain - of AF_INET6: - var sockAddress: Sockaddr_in6 - adaptRecvFromToDomain(sockAddress, AF_INET6) - of AF_INET: - var sockAddress: Sockaddr_in - adaptRecvFromToDomain(sockAddress, AF_INET) - else: - raise newException(ValueError, "Unknown socket address family") proc skip*(socket: Socket, size: int, timeout = -1) = ## Skips `size` amount of bytes. @@ -1762,29 +1808,30 @@ proc sendTo*(socket: Socket, address: string, port: Port, ## This is the high-level version of the above `sendTo` function. socket.sendTo(address, port, cstring(data), data.len, socket.domain) -proc sendTo*(socket: Socket, address: IpAddress, port: Port, - data: string, flags = 0'i32): int {. - discardable, tags: [WriteIOEffect].} = - ## This proc sends `data` to the specified `IpAddress` and returns - ## the number of bytes written. - ## - ## Generally for use with connection-less (UDP) sockets. - ## - ## If an error occurs an OSError exception will be raised. - ## - ## This is the high-level version of the above `sendTo` function. - assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket") - assert(not socket.isClosed, "Cannot `sendTo` on a closed socket") +when defined(zephyr): + proc sendTo*(socket: Socket, address: IpAddress, port: Port, + data: string, flags = 0'i32): int {. + discardable, tags: [WriteIOEffect].} = + ## This proc sends `data` to the specified `IpAddress` and returns + ## the number of bytes written. + ## + ## Generally for use with connection-less (UDP) sockets. + ## + ## If an error occurs an OSError exception will be raised. + ## + ## This is the high-level version of the above `sendTo` function. + assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket") + assert(not socket.isClosed, "Cannot `sendTo` on a closed socket") - var sa: Sockaddr_storage - var sl: SockLen - toSockAddr(address, port, sa, sl) - result = sendto(socket.fd, cstring(data), data.len().cint, flags.cint, - cast[ptr SockAddr](addr sa), sl) + var sa: Sockaddr_storage + var sl: SockLen + toSockAddr(address, port, sa, sl) + result = sendto(socket.fd, cstring(data), data.len().cint, flags.cint, + cast[ptr SockAddr](addr sa), sl) - if result == -1'i32: - let osError = osLastError() - raiseOSError(osError) + if result == -1'i32: + let osError = osLastError() + raiseOSError(osError) proc isSsl*(socket: Socket): bool = diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim index f912e68810..21afa33dea 100644 --- a/tests/stdlib/tnet_ll.nim +++ b/tests/stdlib/tnet_ll.nim @@ -41,7 +41,10 @@ suite "inet_ntop tests": var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001] var buff: array[0..255, char] - let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), buff[0].addr, buff.len.int32) + when defined(zephyr): + let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), buff[0].addr, buff.len.int32) + else: + let r = inet_ntop(AF_INET6, ip6[0].addr, buff[0].addr, buff.sizeof.int32) let res = if r == nil: "" else: $r check: not ipv6Support or res == "10:110:20:120:30:130:40:140"