diff options
author | Dominik Picheta <dominikpicheta@googlemail.com> | 2015-06-29 20:11:21 +0100 |
---|---|---|
committer | Dominik Picheta <dominikpicheta@googlemail.com> | 2015-06-29 20:11:21 +0100 |
commit | 615defb1a9f4739f365ff56321cec0b1a0d1fde2 (patch) | |
tree | f3e3086032752281f616258d39466cb49424c6d2 /lib | |
parent | c16d153ff53732331e7a017a29fc13ccb681a402 (diff) | |
download | Nim-615defb1a9f4739f365ff56321cec0b1a0d1fde2.tar.gz |
Fixes socket problems on Windows and normalises some names.
Ref #2976. Ref #2003. See news.txt for details.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/asyncdispatch.nim | 33 | ||||
-rw-r--r-- | lib/pure/asyncnet.nim | 37 | ||||
-rw-r--r-- | lib/pure/net.nim | 37 | ||||
-rw-r--r-- | lib/pure/rawsockets.nim | 19 |
4 files changed, 72 insertions, 54 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 547880f06..3d1992244 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 = rawsockets.AF_INET): Future[void] = + domain = rawsockets.AF_INET): Future[void] = ## Connects ``socket`` to server at ``address:port``. ## ## Returns a ``Future`` which will complete when the connection succeeds @@ -492,14 +492,14 @@ when defined(windows) or defined(nimdoc): var retFuture = newFuture[void]("connect") # Apparently ``ConnectEx`` expects the socket to be initially bound: var saddr: Sockaddr_in - saddr.sin_family = int16(toInt(af)) + saddr.sin_family = int16(toInt(domain)) saddr.sin_port = 0 saddr.sin_addr.s_addr = INADDR_ANY if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)), sizeof(saddr).SockLen) < 0'i32: raiseOSError(osLastError()) - var aiList = getAddrInfo(address, port, af) + var aiList = getAddrInfo(address, port, domain) var success = false var lastError: OSErrorCode var it = aiList @@ -855,17 +855,17 @@ when defined(windows) or defined(nimdoc): return retFuture - proc newAsyncRawSocket*(domain, typ, protocol: cint): AsyncFD = + proc newAsyncRawSocket*(domain, sockType, protocol: cint): AsyncFD = ## Creates a new socket and registers it with the dispatcher implicitly. - result = newRawSocket(domain, typ, protocol).AsyncFD + result = newRawSocket(domain, sockType, protocol).AsyncFD result.SocketHandle.setBlocking(false) register(result) proc newAsyncRawSocket*(domain: Domain = rawsockets.AF_INET, - typ: SockType = SOCK_STREAM, + sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP): AsyncFD = ## Creates a new socket and registers it with the dispatcher implicitly. - result = newRawSocket(domain, typ, protocol).AsyncFD + result = newRawSocket(domain, sockType, protocol).AsyncFD result.SocketHandle.setBlocking(false) register(result) @@ -928,17 +928,18 @@ else: var data = PData(fd: fd, readCBs: @[], writeCBs: @[]) p.selector.register(fd.SocketHandle, {}, data.RootRef) - proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): AsyncFD = - result = newRawSocket(domain, typ, protocol).AsyncFD + proc newAsyncRawSocket*(domain: cint, sockType: cint, + protocol: cint): AsyncFD = + result = newRawSocket(domain, sockType, protocol).AsyncFD result.SocketHandle.setBlocking(false) when defined(macosx): result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1) register(result) proc newAsyncRawSocket*(domain: Domain = AF_INET, - typ: SockType = SOCK_STREAM, + sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP): AsyncFD = - result = newRawSocket(domain, typ, protocol).AsyncFD + result = newRawSocket(domain, sockType, protocol).AsyncFD result.SocketHandle.setBlocking(false) when defined(macosx): result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1) @@ -1009,7 +1010,7 @@ else: processTimers(p) proc connect*(socket: AsyncFD, address: string, port: Port, - af_unused = AF_INET): Future[void] = + domain = AF_INET): Future[void] = var retFuture = newFuture[void]("connect") proc cb(fd: AsyncFD): bool = @@ -1017,8 +1018,8 @@ else: retFuture.complete() return true - var sockDomain = getSockDomain(socket.SocketHandle) - var aiList = getAddrInfo(address, port, sockDomain) + assert getSockDomain(socket.SocketHandle) == domain + var aiList = getAddrInfo(address, port, domain) var success = false var lastError: OSErrorCode var it = aiList @@ -1496,8 +1497,8 @@ macro async*(prc: stmt): stmt {.immediate.} = result[6] = outerProcBody #echo(treeRepr(result)) - #if prc[0].getName == "test": - # echo(toStrLit(result)) + if prc[0].getName == "getAsync": + echo(toStrLit(result)) proc recvLine*(socket: AsyncFD): Future[string] {.async.} = ## Reads a line of data from ``socket``. Returned future will complete once diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index d7ac60147..cfd3d7666 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -85,35 +85,44 @@ type bioIn: BIO bioOut: BIO of false: nil + domain: Domain + sockType: SockType + protocol: Protocol AsyncSocket* = ref AsyncSocketDesc {.deprecated: [PAsyncSocket: AsyncSocket].} -# TODO: Save AF, domain etc info and reuse it in procs which need it like connect. - -proc newAsyncSocket*(fd: AsyncFD, buffered = true): AsyncSocket = +proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket = ## Creates a new ``AsyncSocket`` based on the supplied params. assert fd != osInvalidSocket.AsyncFD new(result) result.fd = fd.SocketHandle result.isBuffered = buffered + result.domain = domain + result.sockType = sockType + result.protocol = protocol if buffered: result.currPos = 0 -proc newAsyncSocket*(domain: Domain = AF_INET6, typ: SockType = SOCK_STREAM, +proc newAsyncSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket = ## Creates a new asynchronous socket. ## ## This procedure will also create a brand new file descriptor for ## this socket. - result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered) + result = newAsyncSocket(newAsyncRawSocket(domain, sockType, protocol), domain, + sockType, protocol, buffered) -proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket = +proc newAsyncSocket*(domain, sockType, protocol: cint, + buffered = true): AsyncSocket = ## Creates a new asynchronous socket. ## ## This procedure will also create a brand new file descriptor for ## this socket. - result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered) + result = newAsyncSocket(newAsyncRawSocket(domain, sockType, protocol), + Domain(domain), SockType(sockType), Protocol(protocol), buffered) when defined(ssl): proc getSslError(handle: SslPtr, err: cint): cint = @@ -169,13 +178,12 @@ when defined(ssl): let err = getSslError(socket.sslHandle, opResult.cint) yield appeaseSsl(socket, flags, err.cint) -proc connect*(socket: AsyncSocket, address: string, port: Port, - af = AF_INET) {.async.} = +proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} = ## Connects ``socket`` to server at ``address:port``. ## ## Returns a ``Future`` which will complete when the connection succeeds ## or an error occurs. - await connect(socket.fd.AsyncFD, address, port, af) + await connect(socket.fd.AsyncFD, address, port, socket.domain) if socket.isSsl: when defined(ssl): let flags = {SocketFlag.SafeDisconn} @@ -287,7 +295,8 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}): retFuture.fail(future.readError) else: let resultTup = (future.read.address, - newAsyncSocket(future.read.client, socket.isBuffered)) + newAsyncSocket(future.read.client, socket.domain, + socket.sockType, socket.protocol, socket.isBuffered)) retFuture.complete(resultTup) return retFuture @@ -423,17 +432,15 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {. ## Binds ``address``:``port`` to the socket. ## ## If ``address`` is "" then ADDR_ANY will be bound. - var sockDomain = getSockDomain(socket.fd) - var realaddr = address if realaddr == "": - case sockDomain + case socket.domain of AF_INET6: realaddr = "::" of AF_INET: realaddr = "0.0.0.0" else: raiseOSError("Unknown socket address family and no address specified to bindAddr") - var aiList = getAddrInfo(realaddr, port, sockDomain) + var aiList = getAddrInfo(realaddr, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: dealloc(aiList) raiseOSError(osLastError()) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 29e115da1..d9f4845f3 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -64,6 +64,9 @@ type sslPeekChar: char of false: nil lastError: OSErrorCode ## stores the last error on this socket + domain: Domain + sockType: SockType + protocol: Protocol Socket* = ref SocketImpl @@ -124,33 +127,39 @@ proc toOSFlags*(socketFlags: set[SocketFlag]): cint = result = result or MSG_PEEK of SocketFlag.SafeDisconn: continue -proc newSocket*(fd: SocketHandle, buffered = true): Socket = +proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP, buffered = true): Socket = ## Creates a new socket as specified by the params. assert fd != osInvalidSocket new(result) result.fd = fd result.isBuffered = buffered + result.domain = domain + result.sockType = sockType + result.protocol = protocol if buffered: result.currPos = 0 -proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket = +proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket = ## Creates a new socket. ## ## If an error occurs EOS will be raised. - let fd = newRawSocket(domain, typ, protocol) + let fd = newRawSocket(domain, sockType, protocol) if fd == osInvalidSocket: raiseOSError(osLastError()) - result = newSocket(fd, buffered) + result = newSocket(fd, domain.Domain, sockType.SockType, protocol.Protocol, + buffered) -proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, +proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP, buffered = true): Socket = ## Creates a new socket. ## ## If an error occurs EOS will be raised. - let fd = newRawSocket(domain, typ, protocol) + let fd = newRawSocket(domain, sockType, protocol) if fd == osInvalidSocket: raiseOSError(osLastError()) - result = newSocket(fd, buffered) + result = newSocket(fd, domain, sockType, protocol, buffered) when defined(ssl): CRYPTO_malloc_init() @@ -371,7 +380,7 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {. sizeof(name).SockLen) < 0'i32: raiseOSError(osLastError()) else: - var aiList = getAddrInfo(address, port, AF_INET) + var aiList = getAddrInfo(address, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: dealloc(aiList) raiseOSError(osLastError()) @@ -532,15 +541,15 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) { var valuei = cint(if value: 1 else: 0) setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) -proc connect*(socket: Socket, address: string, port = Port(0), - af: Domain = AF_INET) {.tags: [ReadIOEffect].} = +proc connect*(socket: Socket, address: string, + port = Port(0)) {.tags: [ReadIOEffect].} = ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a ## host name. If ``address`` is a host name, this function will try each IP ## of that host name. ``htons`` is already performed on ``port`` so you must ## not do it. ## ## If ``socket`` is an SSL socket a handshake will be automatically performed. - var aiList = getAddrInfo(address, port, af) + var aiList = getAddrInfo(address, port, socket.domain) # try all possibilities: var success = false var lastError: OSErrorCode @@ -992,15 +1001,15 @@ proc connectAsync(socket: Socket, name: string, port = Port(0), dealloc(aiList) if not success: raiseOSError(lastError) -proc connect*(socket: Socket, address: string, port = Port(0), timeout: int, - af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} = +proc connect*(socket: Socket, address: string, port = Port(0), + timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} = ## Connects to server as specified by ``address`` on port specified by ``port``. ## ## The ``timeout`` paremeter specifies the time in milliseconds to allow for ## the connection to the server to be made. socket.fd.setBlocking(false) - socket.connectAsync(address, port, af) + socket.connectAsync(address, port, socket.domain) var s = @[socket.fd] if selectWrite(s, timeout) != 1: raise newException(TimeoutError, "Call to 'connect' timed out.") diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index d0e3b4cf1..349b0d97a 100644 --- a/lib/pure/rawsockets.nim +++ b/lib/pure/rawsockets.nim @@ -157,17 +157,17 @@ else: result = cint(ord(p)) -proc newRawSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, +proc newRawSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP): SocketHandle = ## Creates a new socket; returns `InvalidSocket` if an error occurs. - socket(toInt(domain), toInt(typ), toInt(protocol)) + socket(toInt(domain), toInt(sockType), toInt(protocol)) -proc newRawSocket*(domain: cint, typ: cint, protocol: cint): SocketHandle = +proc newRawSocket*(domain: cint, sockType: cint, protocol: cint): SocketHandle = ## Creates a new socket; returns `InvalidSocket` if an error occurs. ## ## Use this overload if one of the enums specified above does ## not contain what you need. - socket(domain, typ, protocol) + socket(domain, sockType, protocol) proc close*(socket: SocketHandle) = ## closes a socket. @@ -190,16 +190,17 @@ proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ReadIOEff else: result = posix.listen(socket, cint(backlog)) -proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockType = SOCK_STREAM, - prot: Protocol = IPPROTO_TCP): ptr AddrInfo = +proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): ptr AddrInfo = ## ## ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``! var hints: AddrInfo result = nil - hints.ai_family = toInt(af) - hints.ai_socktype = toInt(typ) - hints.ai_protocol = toInt(prot) + hints.ai_family = toInt(domain) + hints.ai_socktype = toInt(sockType) + hints.ai_protocol = toInt(protocol) hints.ai_flags = AI_V4MAPPED var gaiResult = getaddrinfo(address, $port, addr(hints), result) if gaiResult != 0'i32: |