130 lines
3.7 KiB
Crystal
130 lines
3.7 KiB
Crystal
require "option_parser"
|
|
require "ipc"
|
|
require "socket"
|
|
require "./colors"
|
|
|
|
class WrappedTCPFileDescriptor < TCPSocket
|
|
# do not close the connection when garbage collected!!
|
|
def finalize
|
|
# puts "WrappedTCPFileDescriptor garbage collection!!"
|
|
# super
|
|
end
|
|
end
|
|
|
|
service_name = "tcp"
|
|
port_to_listen = 1234
|
|
|
|
OptionParser.parse do |parser|
|
|
parser.on "-p port", "--port port", "Port to listen on." do |port|
|
|
port_to_listen = port.to_u16
|
|
end
|
|
|
|
parser.on "-s service-name", "--service-name service-name", "Service name." do |name|
|
|
service_name = name
|
|
end
|
|
|
|
parser.on "-h", "--help", "Show this help" do
|
|
puts parser
|
|
exit 0
|
|
end
|
|
end
|
|
|
|
|
|
fdlist_client = [] of TCPSocket
|
|
fdlist = [] of TCPSocket
|
|
|
|
server = TCPServer.new("localhost", port_to_listen)
|
|
service = IPC::SwitchingService.new service_name
|
|
service << server.fd
|
|
|
|
service.loop do |event|
|
|
# TODO: remove closed tcp connections
|
|
fdlist_client.select do |x| ! x.closed? end
|
|
case event
|
|
when IPC::Event::Connection
|
|
puts "#{CBLUE}IPC::Event::Connection#{CRESET}"
|
|
when IPC::Event::Disconnection
|
|
puts "#{CBLUE}IPC::Event::Disconnection#{CRESET}"
|
|
when IPC::Event::ExtraSocket
|
|
puts "#{CBLUE}IPC::Event::ExtraSocket#{CRESET}"
|
|
|
|
if server.fd == event.connection.fd
|
|
client = server.accept
|
|
fdlist << client
|
|
service << client.fd
|
|
puts "#{CBLUE}new client: #{client.fd}#{CRESET}"
|
|
next
|
|
end
|
|
|
|
# since it's an external communication
|
|
# we have to read the message here, it's not handled by default in libipc
|
|
client = WrappedTCPFileDescriptor.new(fd: event.connection.fd, family: Socket::Family::INET)
|
|
message = client.gets
|
|
if message.nil?
|
|
# disconnection
|
|
puts "#{CBLUE}disconnection of client #{event.connection.fd}#{CRESET}"
|
|
service.remove_fd event.connection.fd
|
|
fdlist.select do |x| x.fd != event.connection.fd end
|
|
client.close
|
|
else
|
|
message.chomp
|
|
puts "#{CORANGE}message from client #{client.fd} (#{message.size} bytes): #{message}#{CRESET}"
|
|
begin
|
|
requested_service = message
|
|
newservice = IPC::Connection.new requested_service
|
|
service << newservice.fd
|
|
service.switch.add event.connection.fd, newservice.fd
|
|
client << "OK\n"
|
|
rescue e
|
|
puts "#{CRED}Exception during connection to the service: #{e}#{CRESET}"
|
|
end
|
|
# client << message
|
|
end
|
|
when IPC::Event::Switch
|
|
puts "\033[36mIPC::Event::Switch#{CRESET}: from fd #{event.connection.fd}"
|
|
|
|
# IPC::Event::Message has to be the last entry
|
|
# because ExtraSocket and Switch inherit from Message class
|
|
when IPC::Event::Message
|
|
puts "#{CBLUE}IPC::Event::Message#{CRESET}: #{event.connection.fd}"
|
|
puts "\033[33mconnection to the service: #{String.new event.message.payload}\033[00m"
|
|
|
|
begin
|
|
# should be in the format: service-name IP port
|
|
payload = String.new event.message.payload
|
|
uri = URI.parse payload.chomp
|
|
host = uri.host
|
|
port = uri.port
|
|
host ||= "localhost"
|
|
port ||= 9000
|
|
|
|
requested_service = uri.path.lchop
|
|
|
|
newservice = TCPSocket.new(host, port)
|
|
puts "sending the requested service to the remote tcpd: #{requested_service}"
|
|
newservice << "#{requested_service}\n"
|
|
|
|
puts "waiting for a response from the remote tcpd"
|
|
response = newservice.gets
|
|
if response.nil?
|
|
raise "#{CRED}No response from the tcpd server#{CRESET}"
|
|
end
|
|
response.chomp
|
|
puts "#{CGREEN}response from the remote tcpd: #{CRESET}#{response}"
|
|
|
|
# TODO: when to remove this? This has to happen, memory leak otherwise
|
|
# XXX: hint, check after a select for all dead connections
|
|
fdlist_client << newservice
|
|
|
|
# newservice = IPC::Connection.new requested_service
|
|
service << newservice.fd
|
|
service.switch.add event.connection.fd, newservice.fd
|
|
# service.switch.print
|
|
event.connection.send 1.to_u8, "OK"
|
|
rescue e
|
|
puts "\033[31mException: #{e}"
|
|
event.connection.close
|
|
end
|
|
end
|
|
end
|