From c20ac1d72baba2967b46135e292dbf6e43aa53e0 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Mon, 29 Aug 2022 19:00:00 +0000 Subject: [PATCH 1/2] Add address consistency test --- .../test/scala/epollcat/tcp/TcpSuite.scala | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/shared/src/test/scala/epollcat/tcp/TcpSuite.scala b/tests/shared/src/test/scala/epollcat/tcp/TcpSuite.scala index bd3e3de..ad0ea37 100644 --- a/tests/shared/src/test/scala/epollcat/tcp/TcpSuite.scala +++ b/tests/shared/src/test/scala/epollcat/tcp/TcpSuite.scala @@ -57,6 +57,9 @@ class TcpSuite extends EpollcatSuite { def localAddress: IO[SocketAddress] = IO(ch.getLocalAddress()) + + def remoteAddress: IO[SocketAddress] = + IO(ch.getRemoteAddress()) } object IOSocketChannel { @@ -159,6 +162,26 @@ class TcpSuite extends EpollcatSuite { } } + test("local and remote addresses") { + IOServerSocketChannel.open.evalTap(_.bind(new InetSocketAddress("127.0.0.1", 0))).use { + server => + IOSocketChannel.open.use { clientCh => + server.localAddress.flatMap(clientCh.connect(_)) *> + server.accept.use { serverCh => + for { + serverLocal <- serverCh.localAddress + serverRemote <- serverCh.remoteAddress + clientLocal <- clientCh.localAddress + clientRemote <- clientCh.remoteAddress + } yield { + assertEquals(clientRemote, serverLocal) + assertEquals(serverRemote, clientLocal) + } + } + } + } + } + test("options") { IOSocketChannel.open.use { ch => ch.setOption(StandardSocketOptions.SO_REUSEADDR, java.lang.Boolean.TRUE) *> From 33adcdb72f6d8e1dd4d233e6c5ac3bebd00b015f Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Fri, 2 Sep 2022 22:21:52 +0000 Subject: [PATCH 2/2] Fix `getRemoteAddress()` --- .../net/EpollAsyncSocketChannel.scala | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/net/src/main/scala/epollcat/internal/net/EpollAsyncSocketChannel.scala b/net/src/main/scala/epollcat/internal/net/EpollAsyncSocketChannel.scala index 8516987..cccf173 100644 --- a/net/src/main/scala/epollcat/internal/net/EpollAsyncSocketChannel.scala +++ b/net/src/main/scala/epollcat/internal/net/EpollAsyncSocketChannel.scala @@ -21,6 +21,7 @@ import epollcat.unsafe.EpollRuntime import java.io.IOException import java.net.ConnectException +import java.net.InetAddress import java.net.InetSocketAddress import java.net.SocketAddress import java.net.SocketOption @@ -36,6 +37,7 @@ import scala.scalanative.annotation.stub import scala.scalanative.libc.errno import scala.scalanative.posix import scala.scalanative.posix.netdbOps._ +import scala.scalanative.posix.netinet.inOps._ import scala.scalanative.unsafe._ import scala.scalanative.unsigned._ @@ -45,7 +47,6 @@ final class EpollAsyncSocketChannel private (fd: Int) extends AsynchronousSocket private[this] var _isOpen: Boolean = true private[this] var outputShutdown: Boolean = false - private[this] var remoteAddress: SocketAddress = null private[this] var readReady: Boolean = false private[this] var readCallback: Runnable = null private[this] var writeReady: Boolean = false @@ -85,7 +86,22 @@ final class EpollAsyncSocketChannel private (fd: Int) extends AsynchronousSocket this } - def getRemoteAddress(): SocketAddress = remoteAddress + def getRemoteAddress(): SocketAddress = { + val addr = stackalloc[posix.netinet.in.sockaddr_in]() + val len = stackalloc[posix.sys.socket.socklen_t]() + !len = sizeof[posix.sys.socket.sockaddr].toUInt + if (posix + .sys + .socket + .getpeername(fd, addr.asInstanceOf[Ptr[posix.sys.socket.sockaddr]], len) == -1) + throw new IOException(s"getpeername: ${errno.errno}") + val port = posix.arpa.inet.htons(addr.sin_port).toInt + val addrBytes = addr.sin_addr.at1.asInstanceOf[Ptr[Byte]] + val inetAddr = InetAddress.getByAddress( + Array(addrBytes(0), addrBytes(1), addrBytes(2), addrBytes(3)) + ) + new InetSocketAddress(inetAddr, port) + } @stub def read[A]( @@ -214,7 +230,6 @@ final class EpollAsyncSocketChannel private (fd: Int) extends AsynchronousSocket return handler.failed(new IOException(s"getsockopt: ${errno.errno}"), attachment) if (!optval == 0) { - remoteAddress = remote handler.completed(null, attachment) } else { val ex = !optval match {