require "ipc" require "hexa" # TODO: Write documentation for `IPCProxy` module IPCProxy VERSION = "0.1.0" @@proxy_name = "proxy" @@proxied_service = "pong" def self.start @@proxied_service = ARGV[0] if ARGV.size >= 1 @@proxy_name = ARGV[1] if ARGV.size >= 2 puts "proxy named #{@@proxy_name} for service #{@@proxied_service}" puts "removing keepalive messages" ipc_proxy = IPC.new() ipc_proxy.service_init @@proxy_name ipc_proxy.timer 10_000 timer = 0 ipc_proxy.loop do |event| begin case event.type when LibIPC::EventType::Timer STDOUT.write "Timer #{timer}.\r".to_slice STDOUT.flush timer += 1 when LibIPC::EventType::Connection fd = ipc_proxy.connect @@proxied_service ipc_proxy.add_switch event.newfd, fd input = -> fn_input( LibC::Int, LibC::Char*, LibC::UInt64T*) output = -> fn_output(LibC::Int, LibC::Char*, LibC::UInt64T ) ipc_proxy.switch_callbacks event.newfd, input, output puts "New connection (#{event.newfd}) now automatically switched to '#{@@proxied_service}' (#{fd})!" when LibIPC::EventType::Disconnection puts "Disconnection from #{event.fd}." when LibIPC::EventType::MessageTx puts "Message sent to #{event.fd}." when LibIPC::EventType::MessageRx puts "Message received from #{event.fd}." when LibIPC::EventType::SwitchRx #puts "Switch message received from #{event.fd}." when LibIPC::EventType::SwitchTx #puts "Switch message sent to #{event.fd}." when LibIPC::EventType::Error puts "And error occured on fd #{event.fd}." else puts "Unhandled IPC event: #{event.class}." if event.responds_to?(:fd) puts "closing #{event.fd}" ipc_proxy.close event.fd end end rescue exception puts "exception: #{typeof(exception)} - #{exception.message}" end end end end def read_input(fd : LibC::Int, buffer : LibC::Char*, buflen : LibC::UInt64T*) : LibC::Char io = IO::FileDescriptor.new fd, close_on_finalize: false slice = Bytes.new buffer, buflen.value len = io.read slice buflen.value = len.to_u64 return 2_u8 if (len == 0) 0_u8 rescue e puts "read_input exception! #{e}" 1_u8 end def keepalive?(buffer : LibC::Char*) : Bool return (buffer[4] == 250) end def print_hexa(buffer : LibC::Char*, buflen : LibC::UInt64T, title : String) hexa = Hexa.new 50_000 bytes = Bytes.new buffer, buflen puts hexa.dump title, bytes end def fn_input(fd : LibC::Int, buffer : LibC::Char*, buflen : LibC::UInt64T*) : LibC::Char # First, get the content. ret = read_input fd, buffer, buflen return ret if ret != 0 # Second, is this a keepalive message? return ret if keepalive? buffer # Finally, print an hexadecimal presentation of the content. print_hexa buffer, buflen.value, "message received from #{fd}" ret end def write_output(fd : LibC::Int, buffer : LibC::Char*, buflen : LibC::UInt64T) : LibC::Char slice = Bytes.new buffer, buflen io = IO::FileDescriptor.new fd, close_on_finalize: false io.write slice io.flush 0_u8 rescue e puts "write_output exception! #{e}" 1_u8 end def fn_output(fd : LibC::Int, buffer : LibC::Char*, buflen : LibC::UInt64T) : LibC::Char unless keepalive? buffer print_hexa buffer, buflen, "message to send to #{fd}" end write_output fd, buffer, buflen end IPCProxy.start