balena/elixir-sippet

receive_request got called but client side still timeouts

jackalcooper opened this issue · 5 comments

Hello hello. First, thanks for implementing this!

I added config Sippet.Core and the receive_request callback got called but the client still timeouts. It is the Telephone macOS client. Could you give me some hint on what to do next?

Thank you!

Hello @jackalcooper.

Some questions:

  • Have you generated a REGISTER response for your app and passed it back to Sippet.Transactions?
  • I didn't provide a Digest authentication function, how are you authenticating the application?
  • Another possibility is that the app is not accepting the response because it is considered invalid, can you check this?

If you share some code maybe I could provide better answers to your case.

Thanks for your hints. It connects now!

The code is fairly simple actually. I didn't find Sippet.Message.to_response/2 and tried to build a request by myself and it fails.

    def receive_request(incoming_request, server_key) do
        outgoing_response = incoming_request |> Sippet.Message.to_response(200)
        Transactions.send_response(outgoing_response, server_key)
    end

I have one question. Why do we need to imperatively call send_response/2? Idiomatically a callback in Erlang or Elixir returns things like {:resp, resp}, {:ok, response} or {:error, reason}.

Why do we need to imperatively call send_response/2?

Because you may need to wait for some other event to happen before answer the request. Your test code fits the case where a SIP response comes in the form of a return value, but there are several cases where this approach don't fit well. For instance, the core of a proxy I have implemented using Sippet maintains a Registry of client and server transactions, so child processes can accumulate requests/responses from different transactions in order to do their job, like handling CANCEL for a previously forwarded INVITE, handling multiple responses for a forked forward, etc.

Idiomatically a callback in Erlang or Elixir returns things like {:resp, resp}, {:ok, response} or {:error, reason}.

Actually the Sippet.Core is a protocol where receive_request/2, receive_response/2 and receive_error/2 can return any term; that means the return value is simply ignored.

The Sippet.Core is indeed a "naked" module, in the sense that there's no creation of processes for handling requests; these callbacks are called directly from other Sippet internal processes. This approach was taken exactly because the user may want to implement really simple cases like yours without having to worry much with processes. Or maybe you don't want to implement a Proxy or a Registrar, but just an User Agent for testing purposes.

Certainly an elaborated code will require creating processes to handle the requests. Say you have to access a database in order to authenticate the REGISTER request; in this case, you may not want to "block" the Sippet.Core calling process in order to avoid processes "starvation" under high load.

I have started the project https://github.com/balena/elixir-sippet-proxy to tackle some common functions and approaches for Proxies. Also, I'm going to add the Registry approach I mentioned above in order to ease Proxy implementations when I get some time.

I think this case is now closed.