diff options
author | Dominik Picheta <dominikpicheta@googlemail.com> | 2015-06-25 22:36:53 +0100 |
---|---|---|
committer | Dominik Picheta <dominikpicheta@googlemail.com> | 2015-06-25 22:38:17 +0100 |
commit | 6109e6a999c0f70b22e84b5ac412f97efc153367 (patch) | |
tree | 3417323664d674eddf0161620763e990328f2118 | |
parent | db42813a9f62743ee61a768e94dcb2f0fcf89466 (diff) | |
download | Nim-6109e6a999c0f70b22e84b5ac412f97efc153367.tar.gz |
Fixes net/asyncdispatch on Windows. Ref #2976. Fixes #2996.
-rw-r--r-- | lib/pure/asyncdispatch.nim | 4 | ||||
-rw-r--r-- | lib/pure/rawsockets.nim | 99 | ||||
-rw-r--r-- | lib/windows/winlean.nim | 3 |
3 files changed, 59 insertions, 47 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 5a059ec8e..547880f06 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -483,7 +483,7 @@ when defined(windows) or defined(nimdoc): RemoteSockaddr, RemoteSockaddrLength) proc connect*(socket: AsyncFD, address: string, port: Port, - af = AF_INET): Future[void] = + af = rawsockets.AF_INET): Future[void] = ## Connects ``socket`` to server at ``address:port``. ## ## Returns a ``Future`` which will complete when the connection succeeds @@ -861,7 +861,7 @@ when defined(windows) or defined(nimdoc): result.SocketHandle.setBlocking(false) register(result) - proc newAsyncRawSocket*(domain: Domain = AF_INET, + proc newAsyncRawSocket*(domain: Domain = rawsockets.AF_INET, typ: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP): AsyncFD = ## Creates a new socket and registers it with the dispatcher implicitly. diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index 9bfe9dab5..bd22af2d1 100644 --- a/lib/pure/rawsockets.nim +++ b/lib/pure/rawsockets.nim @@ -27,9 +27,10 @@ else: import posix export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL, EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET + export Sockaddr_storage export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen, - Sockaddr_in6, Sockaddr_storage, + Sockaddr_in6, inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto export @@ -45,7 +46,7 @@ when defined(macosx): type Port* = distinct uint16 ## port type - + Domain* = enum ## domain, which specifies the protocol family of the ## created socket. Other domains than those that are listed ## here are unsupported. @@ -60,7 +61,7 @@ type SOCK_SEQPACKET = 5 ## reliable sequenced packet service Protocol* = enum ## third argument to `socket` proc - IPPROTO_TCP = 6, ## Transmission control protocol. + IPPROTO_TCP = 6, ## Transmission control protocol. IPPROTO_UDP = 17, ## User datagram protocol. IPPROTO_IP, ## Internet protocol. Unsupported on Windows. IPPROTO_IPV6, ## Internet Protocol Version 6. Unsupported on Windows. @@ -90,15 +91,19 @@ when useWinVersion: const IOCPARM_MASK* = 127 IOC_IN* = int(-2147483648) - FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or + FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or (102 shl 8) or 126 + rawAfInet = winlean.AF_INET + rawAfInet6 = winlean.AF_INET6 - proc ioctlsocket*(s: SocketHandle, cmd: clong, + proc ioctlsocket*(s: SocketHandle, cmd: clong, argptr: ptr clong): cint {. stdcall, importc: "ioctlsocket", dynlib: "ws2_32.dll".} else: let osInvalidSocket* = posix.INVALID_SOCKET + rawAfInet = posix.AF_INET + rawAfInet6 = posix.AF_INET6 proc `==`*(a, b: Port): bool {.borrow.} ## ``==`` for ports. @@ -142,12 +147,12 @@ when not useWinVersion: else: discard else: - proc toInt(domain: Domain): cint = + proc toInt(domain: Domain): cint = result = toU16(ord(domain)) proc toInt(typ: SockType): cint = result = cint(ord(typ)) - + proc toInt(p: Protocol): cint = result = cint(ord(p)) @@ -177,8 +182,8 @@ proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint result = bindSocket(socket, name, namelen) proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ReadIOEffect].} = - ## Marks ``socket`` as accepting connections. - ## ``Backlog`` specifies the maximum length of the + ## Marks ``socket`` as accepting connections. + ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. when useWinVersion: result = winlean.listen(socket, cint(backlog)) @@ -195,7 +200,7 @@ proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockTy hints.ai_family = toInt(af) hints.ai_socktype = toInt(typ) hints.ai_protocol = toInt(prot) - hints.ai_flags = posix.AI_V4MAPPED + hints.ai_flags = AI_V4MAPPED var gaiResult = getaddrinfo(address, $port, addr(hints), result) if gaiResult != 0'i32: when useWinVersion: @@ -206,7 +211,7 @@ proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockTy proc dealloc*(ai: ptr AddrInfo) = freeaddrinfo(ai) -proc ntohl*(x: int32): int32 = +proc ntohl*(x: int32): int32 = ## Converts 32-bit integers from network to host byte order. ## On machines where the host byte order is the same as network byte order, ## this is a no-op; otherwise, it performs a 4-byte swap operation. @@ -236,7 +241,7 @@ proc htons*(x: int16): int16 = result = rawsockets.ntohs(x) proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = - ## Searches the database from the beginning and finds the first entry for + ## 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. ## @@ -250,10 +255,10 @@ proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = 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 + +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. @@ -271,17 +276,17 @@ 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(rawsockets.AF_INET)) if s == nil: raiseOSError(osLastError()) else: - var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, + var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, cint(posix.AF_INET)) if s == nil: raise newException(OSError, $hstrerror(h_errno)) - + result.name = $s.h_name result.aliases = cstringArrayToSeq(s.h_aliases) when useWinVersion: @@ -296,7 +301,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) -proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = +proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = ## This function will lookup the IP address of a hostname. when useWinVersion: var s = winlean.gethostbyname(name) @@ -324,9 +329,9 @@ proc getSockDomain*(socket: SocketHandle): Domain = if getsockname(socket, cast[ptr SockAddr](addr(name)), addr(namelen)) == -1'i32: raiseOSError(osLastError()) - if name.sa_family == posix.AF_INET: + if name.sa_family == rawAfInet: result = AF_INET - elif name.sa_family == posix.AF_INET6: + elif name.sa_family == rawAfInet6: result = AF_INET6 else: raise newException(OSError, "unknown socket family in getSockFamily") @@ -334,19 +339,23 @@ proc getSockDomain*(socket: SocketHandle): Domain = proc getAddrString*(sockAddr: ptr SockAddr): string = ## return the string representation of address within sockAddr - if sockAddr.sa_family == posix.AF_INET: + if sockAddr.sa_family == rawAfInet: result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr) - elif sockAddr.sa_family == posix.AF_INET6: - var v6addr = cast[ptr Sockaddr_in6](sockAddr).sin6_addr - result = newString(posix.INET6_ADDRSTRLEN) - discard posix.inet_ntop(posix.AF_INET6, addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr, result.cstring, result.len.int32) - if posix.IN6_IS_ADDR_V4MAPPED(addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr) != 0: - result = result.substr("::ffff:".len) + elif sockAddr.sa_family == rawAfInet6: + when not useWinVersion: + # TODO: Windows + var v6addr = cast[ptr Sockaddr_in6](sockAddr).sin6_addr + 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.IN6_IS_ADDR_V4MAPPED(addr6) != 0: + result = result.substr("::ffff:".len) else: raise newException(OSError, "unknown socket family in getAddrString") -proc getSockName*(socket: SocketHandle): Port = +proc getSockName*(socket: SocketHandle): Port = ## returns the socket's associated port number. var name: Sockaddr_in when useWinVersion: @@ -362,11 +371,11 @@ proc getSockName*(socket: SocketHandle): Port = result = Port(rawsockets.ntohs(name.sin_port)) proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {. - tags: [ReadIOEffect].} = + tags: [ReadIOEffect].} = ## getsockopt for integer options. var res: cint var size = sizeof(res).SockLen - if getsockopt(socket, cint(level), cint(optname), + if getsockopt(socket, cint(level), cint(optname), addr(res), addr(size)) < 0'i32: raiseOSError(osLastError()) result = int(res) @@ -375,7 +384,7 @@ proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {. tags: [WriteIOEffect].} = ## setsockopt for integer options. var value = cint(optval) - if setsockopt(socket, cint(level), cint(optname), addr(value), + if setsockopt(socket, cint(level), cint(optname), addr(value), sizeof(value).SockLen) < 0'i32: raiseOSError(osLastError()) @@ -402,13 +411,13 @@ proc timeValFromMilliseconds(timeout = 500): Timeval = result.tv_sec = seconds.int32 result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 -proc createFdSet(fd: var TFdSet, s: seq[SocketHandle], m: var int) = +proc createFdSet(fd: var TFdSet, s: seq[SocketHandle], m: var int) = FD_ZERO(fd) - for i in items(s): + for i in items(s): m = max(m, int(i)) FD_SET(i, fd) - -proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = + +proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = var i = 0 var L = s.len while i < L: @@ -422,22 +431,22 @@ proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = proc select*(readfds: var seq[SocketHandle], timeout = 500): int = ## Traditional select function. This function will return the number of ## sockets that are ready to be read from, written to, or which have errors. - ## If there are none; 0 is returned. + ## If there are none; 0 is returned. ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout. - ## + ## ## A socket is removed from the specific ``seq`` when it has data waiting to ## be read/written to or has errors (``exceptfds``). var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) - + var rd: TFdSet var m = 0 createFdSet((rd), readfds, m) - + if timeout != -1: result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv))) else: result = int(select(cint(m+1), addr(rd), nil, nil, nil)) - + pruneSocketSet(readfds, (rd)) proc selectWrite*(writefds: var seq[SocketHandle], @@ -450,16 +459,16 @@ proc selectWrite*(writefds: var seq[SocketHandle], ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for ## an unlimited time. var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) - + var wr: TFdSet var m = 0 createFdSet((wr), writefds, m) - + if timeout != -1: result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv))) else: result = int(select(cint(m+1), nil, addr(wr), nil, nil)) - + pruneSocketSet(writefds, (wr)) when defined(Windows): diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 9f04bab35..24015dd3a 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -723,6 +723,9 @@ template WSAIORW*(x,y): expr = (IOC_INOUT or x or y) const SIO_GET_EXTENSION_FUNCTION_POINTER* = WSAIORW(IOC_WS2,6).DWORD SO_UPDATE_ACCEPT_CONTEXT* = 0x700B + AI_V4MAPPED* = 0x0008 + AF_INET* = 2 + AF_INET6* = 23 var WSAID_CONNECTEX*: GUID = GUID(D1: 0x25a207b9, D2: 0xddf3'i16, D3: 0x4660, D4: [ |