diff --git a/shard.yml b/shard.yml index cfb5da6..131077a 100644 --- a/shard.yml +++ b/shard.yml @@ -8,6 +8,12 @@ authors: description: | High-level Crystal bindings to libipc. +targets: + pongd: + main: tests/pongd.cr + pongc: + main: tests/pongc.cr + libraries: libipc: ">= 0.7" diff --git a/src/ipc/client.cr b/src/ipc/client.cr index 74d962c..31960dc 100644 --- a/src/ipc/client.cr +++ b/src/ipc/client.cr @@ -1,6 +1,6 @@ class IPC::Client < IPC::Context - property server_fd : Int32 + property server_fd : Int32? # By default, this is a client. def initialize(service_name : String) @@ -13,9 +13,23 @@ class IPC::Client < IPC::Context raise Exception.new "error during connection establishment: #{m}" end - @server_fd = server_fd + @server_fd = serverfd # Very important as there are filesystem side-effects. at_exit { close } end + + def read + unless (fd = @server_fd).nil? + message = LibIPC::Message.new + r = LibIPC.ipc_read_fd(fd, pointerof(message)) + if r.error_code != 0 + m = String.new r.error_message.to_slice + raise Exception.new "error reading a message: #{m}" + end + IPC::Message.new pointerof(message) + else + raise "Client not connected to a server" + end + end end diff --git a/src/ipc/context.cr b/src/ipc/context.cr index ba51c28..1b94a4a 100644 --- a/src/ipc/context.cr +++ b/src/ipc/context.cr @@ -110,8 +110,8 @@ class IPC::Context send(fd, utype, Bytes.new(payload.to_unsafe, payload.bytesize)) end - def send(fd : Int32, message : IPC::Message) - send(fd, message.fd, message.utype, message.payload) + def send(message : IPC::Message) + send(message.fd, message.utype, message.payload) end def read(index : UInt32) diff --git a/src/ipc/lowlevel.cr b/src/ipc/lowlevel.cr index e0b9b99..81a586f 100644 --- a/src/ipc/lowlevel.cr +++ b/src/ipc/lowlevel.cr @@ -93,7 +93,7 @@ lib LibIPC # Connection functions. # Context is allocated, ipcd is requested and the connection/initialisation is performed. fun ipc_server_init(ctx : Ctx*, sname : LibC::Char*) : IPCError - fun ipc_connection(Ctx*, LibC::Char*) : IPCError + fun ipc_connection(Ctx*, LibC::Char*, Int32*) : IPCError fun ipc_connection_switched(Ctx*, LibC::Char*, LibC::Int, Pointer(LibC::Int)) : IPCError # ipc_message_copy: pm, @fd, @mtype, @utype, @payload diff --git a/tests/colors.cr b/tests/colors.cr new file mode 100644 index 0000000..4c4d49c --- /dev/null +++ b/tests/colors.cr @@ -0,0 +1,5 @@ +CRED = "\033[31m" +CBLUE = "\033[36m" +CGREEN = "\033[32m" +CRESET = "\033[00m" +CORANGE = "\033[33m" diff --git a/tests/pong.c b/tests/pong.c new file mode 100644 index 0000000..da47189 --- /dev/null +++ b/tests/pong.c @@ -0,0 +1,3 @@ +require "../src/ipc.cr" + +IPC::Client.new "pong" diff --git a/tests/pongc.cr b/tests/pongc.cr new file mode 100644 index 0000000..509c301 --- /dev/null +++ b/tests/pongc.cr @@ -0,0 +1,24 @@ +require "../src/ipc.cr" + +client = IPC::Client.new "pong" + +server_fd = client.server_fd + +if server_fd.nil? + puts "there is no server_fd!!" + exit 1 +end + +message = IPC::Message.new server_fd, 1, 42.to_u8, "salut ça va ?" + +client.send message + +client.loop do |event| + case event + when IPC::Event::MessageReceived + puts "\033[32mthere is a message\033[00m" + puts event.message.to_s + client.close + exit + end +end diff --git a/tests/pongd.cr b/tests/pongd.cr new file mode 100644 index 0000000..b3c3314 --- /dev/null +++ b/tests/pongd.cr @@ -0,0 +1,78 @@ +require "option_parser" +require "../src/ipc.cr" +require "./colors" + +verbosity = 1 +service_name = "pong" +no_response = false + +OptionParser.parse do |parser| + parser.on "-s service_name", "--service-name service_name", "URI" do |optsn| + service_name = optsn + end + + parser.on "-n", "--no-response", "Do not provide any response back." do + no_response = true + end + + parser.on "-v verbosity", "--verbosity verbosity", "Verbosity (0 = nothing is printed, 1 = only events, 2 = events and messages). Default: 1" do |optsn| + verbosity = optsn.to_i + end + + parser.on "-h", "--help", "Show this help" do + puts parser + exit 0 + end +end + +service = IPC::Server.new (service_name) +service.base_timer = 5000 # 5 seconds +service.timer = 5000 # 5 seconds + +service.loop do |event| + case event + when IPC::Event::Timer + if verbosity >= 1 + puts "#{CORANGE}IPC::Event::Timer#{CRESET}" + end + when IPC::Event::Connection + if verbosity >= 1 + puts "#{CBLUE}IPC::Event::Connection#{CRESET}, client: #{event.fd}" + end + when IPC::Event::Disconnection + if verbosity >= 1 + puts "#{CBLUE}IPC::Event::Disconnection#{CRESET}, client: #{event.fd}" + end + when IPC::Event::MessageSent + begin + if verbosity >= 1 + puts "#{CGREEN}IPC::Event::MessageSent#{CRESET}, client: #{event.fd}" + end + rescue e + puts "#{CRED}#{e.message}#{CRESET}" + service.remove_fd event.fd + end + when IPC::Event::MessageReceived + begin + if verbosity >= 1 + puts "#{CGREEN}IPC::Event::MessageReceived#{CRESET}, client: #{event.fd}" + if verbosity >= 2 + m = String.new event.message.payload + puts "#{CBLUE}message type #{event.message.utype}: #{m} #{CRESET}" + end + end + service.send event.message unless no_response + if verbosity >= 2 && ! no_response + puts "#{CBLUE}sending message...#{CRESET}" + end + + rescue e + puts "#{CRED}#{e.message}#{CRESET}" + service.remove_fd event.fd + end + else + if verbosity >= 1 + puts "#{CRED}Exception: message #{event} #{CRESET}" + end + end +end