lib/zmachine/tcp_channel.rb
java_import java.io.IOException
java_import java.net.InetSocketAddress
java_import java.nio.channels.SocketChannel
java_import java.nio.channels.ServerSocketChannel
require 'zmachine/channel'
module ZMachine
class TCPChannel < Channel
def initialize
super
@buffer = Thread.current[:tcp_channel_buffer] ||= ByteBuffer.allocate(1024 * 1024)
end
def selectable_fd
@socket
end
def bind(address, port)
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
address = InetSocketAddress.new(address, port)
@socket = ServerSocketChannel.open
@socket.configure_blocking(false)
@socket.bind(address)
end
def bound?
@socket.is_a?(ServerSocketChannel) && @socket.socket.bound?
end
def accept
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
client_socket = @socket.accept
return unless client_socket
client_socket.configure_blocking(false)
channel = TCPChannel.new
channel.socket = client_socket
channel
end
def connect(address, port)
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
address = InetSocketAddress.new(address, port)
@socket = SocketChannel.open
@socket.configure_blocking(false)
if socket.connect(address)
# Connection returned immediately. Can happen with localhost
# connections.
# WARNING, this code is untested due to lack of available test
# conditions. Ought to be be able to come here from a localhost
# connection, but that doesn't happen on Linux. (Maybe on FreeBSD?)
raise RuntimeError.new("immediate-connect unimplemented")
end
end
def connection_pending?
@socket.connection_pending?
end
def finish_connecting
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
return unless connection_pending?
@socket.finish_connect
end
def connected?
return false if @socket.is_a?(ServerSocketChannel)
@socket.connected?
end
def read_inbound_data
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
@buffer.clear
raise IOException.new("EOF") if @socket.read(@buffer) == -1
@buffer.flip
return if @buffer.limit == 0
data = java.util.Arrays.copyOfRange(@buffer.array, @buffer.position, @buffer.limit)
data = String.from_java_bytes(data) unless @raw
data
end
def close!
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
@socket.close
end
def closed?
@socket.socket.closed?
end
def peer
[@socket.socket.port, @socket.socket.inet_address.host_address]
end
end
end