From 30dbf2e85bb7df6b8e2356f59086fa38c5de3b3c Mon Sep 17 00:00:00 2001 From: Karchnu Date: Sat, 7 Nov 2020 02:40:05 +0100 Subject: [PATCH] New C function, fix a memory leak, more error cases covered. --- src/ipc/context.cr | 51 ++++++++++++++++++++++++++++++--------------- src/ipc/event.cr | 4 ++++ src/ipc/lowlevel.cr | 1 + src/ipc/server.cr | 3 ++- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/ipc/context.cr b/src/ipc/context.cr index 0315f32..4f0c032 100644 --- a/src/ipc/context.cr +++ b/src/ipc/context.cr @@ -4,6 +4,11 @@ class IPC::Context property timer : Int32 = LibIPC::INFTIM getter context : LibIPC::Ctx + # On message reception, the message is contained into the event structure. + # This message is automatically deallocated on the next ipc_wait_event call. + # Therefore, we must keep this structure. + property event = LibIPC::Event.new + def initialize @context = LibIPC::Ctx.new end @@ -41,45 +46,56 @@ class IPC::Context end def wait_event : IPC::Event::Events | Exception - event = LibIPC::Event.new + r = LibIPC.ipc_wait_event self.pointer, pointerof(@event), pointerof(@timer) + + event_type = @event.type.unsafe_as(LibIPC::EventType) - r = LibIPC.ipc_wait_event self.pointer, pointerof(event), pointerof(@timer) if r.error_code != 0 m = String.new r.error_message.to_slice + case event_type + when LibIPC::EventType::Disconnection # User disconnected. + # In this case, error_code may not be 0, disconnections can happen at any time. + return IPC::Event::Disconnection.new @event.origin, @event.index + end + # Special case where the fd is closed. + if r.error_code == 107 + # Baguette::Log.error "ERROR 107: fd #{@event.origin}" + return IPC::Event::Disconnection.new @event.origin, @event.index + else + # Baguette::Log.error "ERROR #{r.error_code}: fd #{@event.origin}" + end return IPC::Exception.new "error waiting for a new event: #{m}" end - eventtype = event.type.unsafe_as(LibIPC::EventType) - - # if event type is Timer, there is no connection nor message - case eventtype + # if event type is Timer, there is no file descriptor nor message + case event_type when LibIPC::EventType::NotSet - return Exception.new "'Event type: not set" + return IPC::Event::EventNotSet.new @event.origin, @event.index when LibIPC::EventType::Error - return IPC::Event::Error.new event.origin, event.index + return IPC::Event::Error.new @event.origin, @event.index when LibIPC::EventType::ExtraSocket # Message received from a non IPC socket. - return IPC::Event::ExtraSocket.new event.origin, event.index + return IPC::Event::ExtraSocket.new @event.origin, @event.index when LibIPC::EventType::Switch # Message to send to a corresponding fd. - return IPC::Event::Switch.new event.origin, event.index + return IPC::Event::Switch.new @event.origin, @event.index when LibIPC::EventType::Connection # New user. - return IPC::Event::Connection.new event.origin, event.index + return IPC::Event::Connection.new @event.origin, @event.index when LibIPC::EventType::Disconnection # User disconnected. - return IPC::Event::Disconnection.new event.origin, event.index + return IPC::Event::Disconnection.new @event.origin, @event.index when LibIPC::EventType::Message # New message. - lowlevel_message = event.message.unsafe_as(Pointer(LibIPC::Message)) + lowlevel_message = @event.message.unsafe_as(Pointer(LibIPC::Message)) ipc_message = IPC::Message.new lowlevel_message - return IPC::Event::MessageReceived.new event.origin, event.index, ipc_message + return IPC::Event::MessageReceived.new @event.origin, @event.index, ipc_message when LibIPC::EventType::LookUp # Client asking for a service through ipcd. # for now, the libipc does not provide lookup events # ipcd uses a simple LibIPC::EventType::Message - return IPC::Event::LookUp.new event.origin, event.index + return IPC::Event::LookUp.new @event.origin, @event.index when LibIPC::EventType::Timer # Timeout in the poll(2) function. return IPC::Event::Timer.new when LibIPC::EventType::Tx # Message sent. - return IPC::Event::MessageSent.new event.origin, event.index + return IPC::Event::MessageSent.new @event.origin, @event.index end - return Exception.new "Cannot understand the event type: #{eventtype}" + return Exception.new "Cannot understand the event type: #{event_type}" end def loop(&block : Proc(IPC::Event::Events|Exception, Nil)) @@ -159,6 +175,7 @@ class IPC::Context def close return if @closed + r = LibIPC.ipc_close_all(self.pointer) if r.error_code != 0 m = String.new r.error_message.to_slice diff --git a/src/ipc/event.cr b/src/ipc/event.cr index 502efb8..c96ef7f 100644 --- a/src/ipc/event.cr +++ b/src/ipc/event.cr @@ -1,6 +1,7 @@ class IPC::Event alias Events = IPC::Event::Timer | + IPC::Event::EventNotSet | IPC::Event::Error | IPC::Event::Connection | IPC::Event::Disconnection | @@ -52,3 +53,6 @@ end class IPC::Event::MessageSent < IPC::Event::Base end +class IPC::Event::EventNotSet < IPC::Event::Base +end + diff --git a/src/ipc/lowlevel.cr b/src/ipc/lowlevel.cr index 82541d3..6bfb7e4 100644 --- a/src/ipc/lowlevel.cr +++ b/src/ipc/lowlevel.cr @@ -151,6 +151,7 @@ lib LibIPC (LibC::Int, LibIPC::Message* -> LibIPC::IPCCB)) fun ipc_ctx_switching_add (ctx : Ctx*, fd1 : LibC::Int, fd2 : LibC::Int) # Void + fun ipc_ctx_switching_del (ctx : Ctx*, fd : LibC::Int) : LibC::Int fun ipc_switching_add (switch : Switchings*, fd1 : LibC::Int, fd2 : LibC::Int) # Void fun ipc_switching_del (switch : Switchings*, fd : LibC::Int ) : LibC::Int fun ipc_switching_get (switch : Switchings*, fd : LibC::Int ) : LibC::Int diff --git a/src/ipc/server.cr b/src/ipc/server.cr index fafd5cb..15d4a01 100644 --- a/src/ipc/server.cr +++ b/src/ipc/server.cr @@ -11,7 +11,8 @@ class IPC::Server < IPC::Context end # Very important as there are filesystem side-effects. - at_exit { close } + # FIXME: for now, let's forget that. + # at_exit { close } end end