From 35e38966751a2f705ec6177346fd05f0ec5471af Mon Sep 17 00:00:00 2001 From: Amit Murthy Date: Fri, 12 May 2017 16:34:05 +0530 Subject: [PATCH] getsockname mirrors UNIX getsockname now. Added getpeername. --- NEWS.md | 5 +++ base/distributed/managers.jl | 2 +- base/exports.jl | 1 + base/socket.jl | 21 ++++++++---- doc/src/stdlib/io-network.md | 1 + test/socket.jl | 63 ++++++++++++------------------------ 6 files changed, 44 insertions(+), 49 deletions(-) diff --git a/NEWS.md b/NEWS.md index a786c3814f2ed..65fc77458a860 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,8 @@ Julia v0.7.0 Release Notes New language features --------------------- + * `getpeername` on a `TCPSocket` returns the address and port of the remote + endpoint of the TCP connection ([#21825]). Language changes @@ -24,6 +26,9 @@ This section lists changes that do not have deprecation warnings. * Passing the same keyword argument multiple times is now a syntax error ([#16937]). + * `getsockname` on a `TCPSocket` now returns the locally bound address and port + of the socket. Previously the address of the remote endpoint was being + returned ([#21825]). Library improvements -------------------- diff --git a/base/distributed/managers.jl b/base/distributed/managers.jl index d7ed15a3e3115..46b422e19f448 100644 --- a/base/distributed/managers.jl +++ b/base/distributed/managers.jl @@ -481,7 +481,7 @@ function bind_client_port(s) s.handle, hton(client_port[]), hton(UInt32(0)), 0) Base.uv_error("bind() failed", err) - _addr, port = Base._sockname(s, true) + _addr, port = getsockname(s) client_port[] = port return s end diff --git a/base/exports.jl b/base/exports.jl index 039c5328f9bb1..376a9704b6d55 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1071,6 +1071,7 @@ export getaddrinfo, gethostname, getipaddr, + getpeername, getsockname, htol, hton, diff --git a/base/socket.jl b/base/socket.jl index 0c4b0996d2830..ae4e055c91325 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -827,7 +827,7 @@ function listenany(host::IPAddr, default_port) sock = TCPServer() if bind(sock, addr) && trylisten(sock) == 0 if default_port == 0 - _addr, port = _sockname(sock, true) + _addr, port = getsockname(sock) return (port, sock) end return (addr.port, sock) @@ -845,15 +845,24 @@ listenany(default_port) = listenany(IPv4(UInt32(0)), default_port) """ getsockname(sock::Union{TCPServer, TCPSocket}) -> (IPAddr, UInt16) -Get the IP address and the port that the given `TCPSocket` is connected to -(or bound to, in the case of `TCPServer`). +Get the IP address and port that the given socket is bound to. """ -getsockname(sock::Union{TCPServer, TCPSocket}) = _sockname(sock, isa(sock, TCPServer)) +getsockname(sock::Union{TCPSocket, TCPServer}) = _sockname(sock, true) -function _sockname(sock, self) + +""" + getpeername(sock::TCPSocket) -> (IPAddr, UInt16) + +Get the IP address and port of the remote endpoint that the given +socket is connected to. Valid only for connected TCP sockets. +""" +getpeername(sock::TCPSocket) = _sockname(sock, false) + +function _sockname(sock, self=true) rport = Ref{Cushort}(0) raddress = zeros(UInt8, 16) rfamily = Ref{Cuint}(0) + if self r = ccall(:jl_tcp_getsockname, Int32, (Ptr{Void}, Ref{Cushort}, Ptr{Void}, Ref{Cuint}), @@ -886,7 +895,7 @@ function _sockname(sock, self) naddr = ntoh(unsafe_load(Ptr{UInt128}(pointer(raddress)), 1)) addr = IPv6(naddr) else - error("unsupported address family: $(getindex(rfamily))") + error(string("unsupported address family: ", getindex(rfamily))) end else error("cannot obtain socket name") diff --git a/doc/src/stdlib/io-network.md b/doc/src/stdlib/io-network.md index cb697abfbac33..88fd2b2cf3bb0 100644 --- a/doc/src/stdlib/io-network.md +++ b/doc/src/stdlib/io-network.md @@ -162,6 +162,7 @@ Base.listen(::Any) Base.listen(::AbstractString) Base.getaddrinfo Base.getsockname +Base.getpeername Base.IPv4 Base.IPv6 Base.nb_available diff --git a/test/socket.jl b/test/socket.jl index 1d215ec237efc..917d3c240a13c 100644 --- a/test/socket.jl +++ b/test/socket.jl @@ -193,56 +193,35 @@ if !is_windows() || Sys.windows_version() >= Sys.WINDOWS_VISTA_VER end begin - default_port = UInt16(11011) - default_addr = IPv4("127.0.0.1") + for (addr, porthint) in [(IPv4("127.0.0.1"), UInt16(11011)), + (IPv6("::1"), UInt16(11012)), (getipaddr(), UInt16(11013))] + port, listen_sock = listenany(addr, porthint) + gsn_addr, gsn_port = getsockname(listen_sock) - sock = Base.TCPServer() - bind(sock,Base.InetAddr(default_addr,default_port)) - listen(sock) + @test addr == gsn_addr + @test port == gsn_port - new_addr, new_port = getsockname(sock) + @test_throws MethodError getpeername(listen_sock) - @test default_addr == new_addr - @test default_port == new_port - close(sock) -end + # connect to it + client_sock = connect(addr, port) + server_sock = accept(listen_sock) -begin - default_port = UInt16(21011) - default_addr = IPv6("::1") + self_client_addr, self_client_port = getsockname(client_sock) + peer_client_addr, peer_client_port = getpeername(client_sock) + self_srvr_addr, self_srvr_port = getsockname(server_sock) + peer_srvr_addr, peer_srvr_port = getpeername(server_sock) - sock = Base.TCPServer() - addr = Base.InetAddr(default_addr,default_port) - bind(sock,addr) - listen(sock) + @test self_client_addr == peer_client_addr == self_srvr_addr == peer_srvr_addr - new_addr, new_port = getsockname(sock) + @test peer_client_port == self_srvr_port + @test peer_srvr_port == self_client_port + @test self_srvr_port != self_client_port - @test default_addr == new_addr - @test default_port == new_port - close(sock) -end - -begin - default_port = UInt16(11011) - default_addr = getipaddr() - - sock = Base.TCPServer() - bind(sock,Base.InetAddr(default_addr,default_port)) - listen(sock) - - @async begin - sleep(1) - ssock = connect(default_addr, default_port) + close(listen_sock) + close(client_sock) + close(server_sock) end - - csock = accept(sock) - new_addr, new_port = getsockname(csock) - - @test default_addr == new_addr - @test new_port > 0 - close(csock) - close(sock) end # Local-machine broadcast