8000 sipsess: add cancel reason to cancel handler by KillingSpark · Pull Request #1309 · baresip/re · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

sipsess: add cancel reason to cancel handler #1309

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

KillingSpark
Copy link
@KillingSpark KillingSpark commented Apr 27, 2025

I want to display the provided reason in Cancel messages to the user of baresip, but as far as I could tell the Cancel messages are not communicated outside of libre. So I added a cancel handler, very similar to all the other handlers.

This is a breaking API change though, so I am not sure if this is the best way to go about this.

Related to this feature request: baresip/baresip#3363

@sreimers sreimers added this to the v3.23.0 milestone Apr 27, 2025
@sreimers sreimers changed the title add cancel handler to sip session to inform clients of cancel reasons sipsess: add cancel reason to cancel handler Apr 27, 2025
@KillingSpark
Copy link
Author

Hi, sorry that it took a few commits more than I'd have liked to get this right, it's my first time contributing to a C project. The CI is now green on my fork (besides the abicheck (because tags aren't transferred when forking but that depends on the version tag being present) and the sonar workflow (because I don't have a sonar token)).

@@ -275,7 +275,7 @@ typedef int(sip_send_h)(enum sip_transp tp, struct sa *src,
typedef int(sip_conn_h)(struct sa *src, const struct sa *dst, struct mbuf *mb,
void *arg);
typedef void(sip_resp_h)(int err, const struct sip_msg *msg, void *arg);
typedef void(sip_cancel_h)(void *arg);
typedef void(sip_cancel_h)(const struct sip_msg *msg, void *arg);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to implement this without breaking the API ?

Copy link
Author
Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could attach the information about the cancellation to the struct sipsess which is passed as the void *arg there. But this isn't the only place the API would have a breaking change. Passing the cancel handlers from the upper layer is also a breaking change and I don't see how that can be avoided.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem, it should be fine to break the API if that is the only option ...
We try to avoid breaking the API, but sometimes you have to do it ...

The void pointer to arg is supposed to be opaque, so that this layer has no
compile-time knowledge about the upper layer.

Another option is to save the Cancel Reason on the SIP-state itself and add
a getter function, something like this:

struct {
    ...
    uint16_t cause;
    char *text;
    ....
};

void sip_get_cancel_reason(struct sip *sip, uint16_t *causep, char **textp);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that would also work, although I would attach it to the struct sip_trans since that's where the cancel handler and the void *arg is stored.

Do you think that would be better? I think passing the message in the cancel handler is the more obvious way. The response handler does this the same way to communicate the related information (like errors or similar) to the upper layer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

either way is fine with me ..

@alfredh
Copy link
Contributor
alfredh commented May 7, 2025

Could you please also add a copy of your SIP signalling, for reference ?

@KillingSpark
Copy link
Author
INVITE sip:REDACT@REDACT;transport=tls SIP/2.0
Call-ID: a01984cd356f30a3c20b3c29b5cacdd9@REDACT
CSeq: 17429 INVITE
From: "+REDACT" <sip:+REDACT@REDACT>;tag=XVPLSfvv5yY
To: "REDACT" <sip:+REDACT@REDACT>
Via: SIP/2.0/TLS REDACT;branch=z9hG4bKtAnn4iOZQS2OYCtGatPSGw
Max-Forwards: 68
Contact: <sip:REDACT@REDACT;transport=tls;ob>
Allow: INVITE,ACK,CANCEL,BYE,REFER,REGISTER,SUBSCRIBE,PUBLISH
Supported: replaces
Content-Type: application/sdp
User-Agent: REDACT
Content-Length: 786

v=0
o=- 1745825554478 1745825554480 IN IP4 REDACT
s=CROWN
c=IN IP4 REDACT
t=0 0
m=audio REDACT RTP/AVP 109 9 8 0 101
a=rtpmap:109 opus/48000/2
a=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1
a=rtpmap:9 G722/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp-xr:voip-metrics stat-summary=loss,dup,jitt
a=crypto:1 AES_256_CM_HMAC_SHA1_80 inline:REDACT
a=crypto:2 AES_256_CM_HMAC_SHA1_32 inline:REDACT
a=crypto:3 AES_CM_128_HMAC_SHA1_80 inline:REDACT
a=crypto:4 AES_CM_128_HMAC_SHA1_32 inline:REDACT

REDACT@REDACT: selected for REDACT
REDACT@REDACT: selected for REDACT
ua: using connection-address REDACT of SDP offer
stream: audio: starting mediaenc 'srtp' (wait_secure=0)
12:51:03.336#
TLS REDACT -> REDACT
SIP/2.0 180 Ringing
Call-ID: a01984cd356f30a3c20b3c29b5cacdd9@REDACT
CSeq: 17429 INVITE
From: "+REDACT" <sip:+REDACT@REDACT>;tag=XVPLSfvv5yY
To: "REDACT" <sip:+REDACT@REDACT>;tag=af4d4c450de16ddf
Via: SIP/2.0/TLS REDACT;branch=z9hG4bKtAnn4iOZQS2OYCtGatPSGw
Server: baresip v3.21.0 (x86_64/Linux)
Contact: <sip:REDACT@REDACT;transport=tls>
Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,NOTIFY,INFO,MESSAGE,UPDATE,REFER
Content-Length: 0


sip:REDACT@REDACT: Incoming call from: +REDACT sip:+REDACT@REDACT - audio-video: sendrecv-inactive - (press 'a' to accept)
12:51:07.636#
TLS REDACT -> REDACT
CANCEL sip:REDACT@REDACT;transport=tls SIP/2.0
Call-ID: a01984cd356f30a3c20b3c29b5cacdd9@REDACT
CSeq: 17429 CANCEL
From: "+REDACT" <sip:+REDACT@REDACT>;tag=XVPLSfvv5yY
To: "REDACT" <sip:+REDACT@REDACT>
Via: SIP/2.0/TLS REDACT;branch=z9hG4bKtAnn4iOZQS2OYCtGatPSGw
Max-Forwards: 70
Contact: <sip:REDACT@REDACT;transport=tls;ob>
Reason: SIP;cause=200;text="Call completed elsewhere"
User-Agent: REDACT
Content-Length: 0

As mentioned in the feature request, the important line here is this: Reason: SIP;cause=200;text="Call completed elsewhere". Currently the upper layers aren't even informed that a cancel happened, just that the call has been closed. Both the information that a cancel happened and the information in that Reason are necessary to give the user a better experience for cases where the call has been picked up on another device (possibly by another person).

@alfredh alfredh removed this from the v3.23.0 milestone May 8, 2025
@@ -30,6 +30,7 @@ typedef void (sipsess_info_h)(struct sip *sip, const struct sip_msg *msg,
typedef void (sipsess_refer_h)(struct sip *sip, const struct sip_msg *msg,
void *arg);
typedef void (sipsess_close_h)(int err, const struct sip_msg *msg, void *arg);
typedef void (sipsess_cancel_h)(const struct sip_msg *msg, void *arg);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you see if you can reuse the close handler here ?

if there is an incoming CANCEL message, the close handler should be called ...

Copy link
Author
@KillingSpark KillingSpark May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They way this currently works is that:

  1. a cancel message comes in
  2. the current sip_cancel_h is called (which is always this static function in accpect.c
static void cancel_handler(void *arg)
{
	struct sipsess *sess = arg;

	(void)sip_treply(&sess->st, sess->sip, sess->msg,
			 487, "Request Terminated");

	sess->peerterm = true;

	if (sess->terminated)
		return;

	sipsess_terminate(sess, ECONNRESET, NULL);
}
  1. This calls sipsess_terminate
void sipsess_terminate(struct sipsess *sess, int err,
		       const struct sip_msg *msg)
{
	sipsess_close_h *closeh;
	void *arg;

	if (sess->terminated)
		return;

	closeh = sess->closeh;
	arg    = sess->arg;

	if (!termwait(sess))
		(void)terminate(sess);

	closeh(err, msg, arg);
}

Note that sipsess_close_h is called here, but the msg is passed in as NULL. I rectified that by changing the signatures of the cancel_handler function and the sip_cancel_h, which is one of the breaking changes.

Afaict this means that the message isn't passed to the close handler, and afaict the session close handler is not called anywhere else.

The only chance I am seeing to avoid any breaking changes is to alter the callsite of the sip_cancel_h here: to call the sip_resp_h with the sip_msg *msg and to somehow call the sipsess_close_h from there.

But that seems like a pretty ugly way of doing things to me for several reasons:

  1. Cancelling a is a pretty important interaction that is quite different from just closing the connection
  2. Hijacking the response handler seems weird, because the cancel isn't a response, it's an additional request that cancels a previous request
  3. This would still change the API just not in a compile breaking way. We add some important semantics to the close handler,
    1. and either we call closeh twice (once from the cancel handler with a NULL message and once from the response handler)
    2. or we need to take care of only calling the handler once which seems prone to producing subtle bugs in future

Other than that we can maybe avoid the sipsess_cancelh by reusing the sipsess_close_h but that would still need the breaking change to the sip_cancel_h so we can have the sip_msg in the cancel handler to pass to sipsess_terminate and in turn to the sipsess_close_h. And if we are already breaking the API anyways I'd favor not hacking support for cancellation into the close handler but to have a separate cancel handler passed from the upper layer.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or, if your question was whether I could use the sipsess_close_h type for cancel handlers: Yeah sure. But why? The cancel handlers are new function args which is a breaking change in any case. Let's give them an appropriate type, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After more thought: I guess I can attach a close_message to the struct sip_trans and pass that to the close handler in terminate_session

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0