Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,14 @@ object TcpClientChannelFactory {
}

// connects the socket; a failure to use its local address, e.g. one whose port is still held by a connection to the
// same remote address and port that closed moments ago, is LocalBindException
// same remote address and port that closed moments ago, is LocalBindException. Nagle's algorithm is off, as in DNP3
// stacks, so a small write goes out at once rather than waiting for the previous one to be acknowledged, which would
// shift the timing the procedures check
def connect(socket: SocketChannel, remote: SocketAddress, local: Option[InetSocketAddress], timeoutMs: Int): Unit =
try socket.socket().connect(remote, timeoutMs)
catch {
try {
socket.setOption(StandardSocketOptions.TCP_NODELAY, java.lang.Boolean.TRUE)
socket.socket().connect(remote, timeoutMs)
} catch {
case ex: java.net.BindException =>
throw new LocalBindException(local.getOrElse(new InetSocketAddress(0)), ex)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-3.0-only
// Copyright Step Function I/O LLC

package io.stepfunc.dnp3c.protocol.channel

import java.net.{ InetAddress, InetSocketAddress, ServerSocket, StandardSocketOptions }
import java.nio.channels.SocketChannel

import scala.util.Using

import org.junit.runner.RunWith
import org.scalatestplus.junit.JUnitRunner
import org.scalatest.matchers.should.Matchers
import org.scalatest.funsuite.AnyFunSuite

@RunWith(classOf[JUnitRunner])
class TcpClientChannelFactoryTest extends AnyFunSuite with Matchers {

test("a connection has Nagle's algorithm off, so each write goes out at once") {
Using.resource(new ServerSocket(0, 1, InetAddress.getLoopbackAddress)) { server =>
Using.resource(SocketChannel.open()) { socket =>
TcpClientChannelFactory.connect(socket, server.getLocalSocketAddress, None, 1000)
socket.getOption(StandardSocketOptions.TCP_NODELAY) should equal(true)
}
}
}
}
Loading