diff options
Diffstat (limited to 'lib/pure/nativesockets.nim')
-rw-r--r-- | lib/pure/nativesockets.nim | 79 |
1 files changed, 55 insertions, 24 deletions
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 0a7ffb3b3..7568408a6 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -12,7 +12,7 @@ # TODO: Clean up the exports a bit and everything else in general. -import os +import os, options when hostOS == "solaris": {.passl: "-lsocket -lnsl".} @@ -52,9 +52,11 @@ type Domain* = enum ## domain, which specifies the protocol family of the ## created socket. Other domains than those that are listed ## here are unsupported. - AF_UNIX, ## for local socket (using a file). Unsupported on Windows. + AF_UNSPEC = 0, ## unspecified domain (can be detected automatically by + ## some procedures, such as getaddrinfo) + AF_UNIX = 1, ## for local socket (using a file). Unsupported on Windows. AF_INET = 2, ## for network protocol IPv4 or - AF_INET6 = 23 ## for network protocol IPv6. + AF_INET6 = when defined(macosx): 30 else: 23 ## for network protocol IPv6. SockType* = enum ## second argument to `socket` proc SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets @@ -113,7 +115,7 @@ proc `==`*(a, b: Port): bool {.borrow.} proc `$`*(p: Port): string {.borrow.} ## returns the port number as a string -proc toInt*(domain: Domain): cint +proc toInt*(domain: Domain): cshort ## Converts the Domain enum to a platform-dependent ``cint``. proc toInt*(typ: SockType): cint @@ -123,12 +125,21 @@ proc toInt*(p: Protocol): cint ## Converts the Protocol enum to a platform-dependent ``cint``. when not useWinVersion: - proc toInt(domain: Domain): cint = + proc toInt(domain: Domain): cshort = case domain - of AF_UNIX: result = posix.AF_UNIX - of AF_INET: result = posix.AF_INET - of AF_INET6: result = posix.AF_INET6 - else: discard + of AF_UNSPEC: result = posix.AF_UNSPEC.cshort + of AF_UNIX: result = posix.AF_UNIX.cshort + of AF_INET: result = posix.AF_INET.cshort + of AF_INET6: result = posix.AF_INET6.cshort + + proc toKnownDomain*(family: cint): Option[Domain] = + ## Converts the platform-dependent ``cint`` to the Domain or none(), + ## if the ``cint`` is not known. + result = if family == posix.AF_UNSPEC: some(Domain.AF_UNSPEC) + elif family == posix.AF_UNIX: some(Domain.AF_UNIX) + elif family == posix.AF_INET: some(Domain.AF_INET) + elif family == posix.AF_INET6: some(Domain.AF_INET6) + else: none(Domain) proc toInt(typ: SockType): cint = case typ @@ -136,7 +147,6 @@ when not useWinVersion: of SOCK_DGRAM: result = posix.SOCK_DGRAM of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET of SOCK_RAW: result = posix.SOCK_RAW - else: discard proc toInt(p: Protocol): cint = case p @@ -146,18 +156,33 @@ when not useWinVersion: of IPPROTO_IPV6: result = posix.IPPROTO_IPV6 of IPPROTO_RAW: result = posix.IPPROTO_RAW of IPPROTO_ICMP: result = posix.IPPROTO_ICMP - else: discard else: - proc toInt(domain: Domain): cint = + proc toInt(domain: Domain): cshort = result = toU16(ord(domain)) + proc toKnownDomain*(family: cint): Option[Domain] = + ## Converts the platform-dependent ``cint`` to the Domain or none(), + ## if the ``cint`` is not known. + result = if family == winlean.AF_UNSPEC: some(Domain.AF_UNSPEC) + elif family == winlean.AF_INET: some(Domain.AF_INET) + elif family == winlean.AF_INET6: some(Domain.AF_INET6) + else: none(Domain) + proc toInt(typ: SockType): cint = result = cint(ord(typ)) proc toInt(p: Protocol): cint = result = cint(ord(p)) +proc toSockType*(protocol: Protocol): SockType = + result = case protocol + of IPPROTO_TCP: + SOCK_STREAM + of IPPROTO_UDP: + SOCK_DGRAM + of IPPROTO_IP, IPPROTO_IPV6, IPPROTO_RAW, IPPROTO_ICMP: + SOCK_RAW proc newNativeSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, @@ -239,7 +264,7 @@ template ntohl*(x: int32): untyped {.deprecated.} = ## **Warning**: This template is deprecated since 0.14.0, IPv4 ## addresses are now treated as unsigned integers. Please use the unsigned ## version of this template. - cast[int32](ntohl(cast[uint32](x))) + cast[int32](nativesockets.ntohl(cast[uint32](x))) proc ntohs*(x: uint16): uint16 = ## Converts 16-bit unsigned integers from network to host byte order. On @@ -255,7 +280,7 @@ template ntohs*(x: int16): untyped {.deprecated.} = ## **Warning**: This template is deprecated since 0.14.0, where port ## numbers became unsigned integers. Please use the unsigned version of ## this template. - cast[int16](ntohs(cast[uint16](x))) + cast[int16](nativesockets.ntohs(cast[uint16](x))) template htonl*(x: int32): untyped {.deprecated.} = ## Converts 32-bit integers from host to network byte order. On machines @@ -392,14 +417,14 @@ proc getHostname*(): string {.tags: [ReadIOEffect].} = proc getSockDomain*(socket: SocketHandle): Domain = ## returns the socket's domain (AF_INET or AF_INET6). - var name: SockAddr + var name: Sockaddr_in6 var namelen = sizeof(name).SockLen if getsockname(socket, cast[ptr SockAddr](addr(name)), addr(namelen)) == -1'i32: raiseOSError(osLastError()) - if name.sa_family == nativeAfInet: + if name.sin6_family == nativeAfInet: result = AF_INET - elif name.sa_family == nativeAfInet6: + elif name.sin6_family == nativeAfInet6: result = AF_INET6 else: raiseOSError(osLastError(), "unknown socket family in getSockFamily") @@ -410,17 +435,23 @@ proc getAddrString*(sockAddr: ptr SockAddr): string = if sockAddr.sa_family == nativeAfInet: result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr) elif sockAddr.sa_family == nativeAfInet6: + let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN + 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: - # TODO: Windows - result = newString(posix.INET6_ADDRSTRLEN) - let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr - discard posix.inet_ntop(posix.AF_INET6, addr6, result.cstring, - result.len.int32) + 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 = result.substr("::ffff:".len) + else: + if winlean.inet_ntop(winlean.AF_INET6, addr6, addr result[0], + result.len.int32) == nil: + raiseOSError(osLastError()) + setLen(result, len(cstring(result))) else: - raiseOSError(osLastError(), "unknown socket family in getAddrString") - + raise newException(IOError, "Unknown socket family in getAddrString") proc getSockName*(socket: SocketHandle): Port = ## returns the socket's associated port number. |