From 623857b1c88627b5e66bb2d0b67894db5382b0fd Mon Sep 17 00:00:00 2001
From: Grzegorz Sluja <grzegorz.sluja@iopsys.eu>
Date: Mon, 1 Aug 2022 12:52:51 +0000
Subject: [PATCH] Add SIPSessionID parameter to CDR records

SIPSessionID is from Session-ID header field either in INVITE for incoming calls or in
200 OK for outgoing calls.
---
 cdr/cdr_beanstalkd.c               |  1 +
 cdr/cdr_csv.c                      |  4 +-
 cdr/cdr_manager.c                  |  3 +-
 cdr/cdr_odbc.c                     |  1 +
 cdr/cdr_radius.c                   | 67 ++++++++++++++++--------------
 include/asterisk/cdr.h             |  2 +
 include/asterisk/channel.h         |  2 +
 include/asterisk/stasis_channels.h |  3 +-
 main/cdr.c                         | 13 +++++-
 main/channel_internal_api.c        | 11 +++++
 main/stasis_channels.c             |  1 +
 res/res_pjsip_session.c            | 21 +++++++++-
 12 files changed, 93 insertions(+), 36 deletions(-)

diff --git a/cdr/cdr_beanstalkd.c b/cdr/cdr_beanstalkd.c
index 156d0a595d..aedb817444 100644
--- a/cdr/cdr_beanstalkd.c
+++ b/cdr/cdr_beanstalkd.c
@@ -216,6 +216,7 @@ static int beanstalk_put(struct ast_cdr *cdr) {
 							   "AMAFlags", S_OR(ast_channel_amaflags2string(cdr->amaflags), ""),
 							   "UniqueID", S_OR(cdr->uniqueid, ""),
 							   "SessionId", cdr->sessionId,
+							   "SIPSessionID", S_OR(cdr->SIPSessionID, ""),
 							   "sipIpAddress", S_OR(cdr->sipIpAddress, ""),
 							   "farEndIPAddress", S_OR(cdr->farEndIPAddress, ""),
 							   "sipResponseCode", cdr->sipResponseCode,
diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c
index 5509d21c03..f5ee32e166 100644
--- a/cdr/cdr_csv.c
+++ b/cdr/cdr_csv.c
@@ -251,8 +251,10 @@ static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr)
 	append_int(buf, cdr->billsec, bufsize);
 	/* Disposition */
 	append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize);
-	/* Session Id */
+	/* SessionId */
 	append_int(buf, cdr->sessionId, bufsize);
+	/* SIPSessionID */
+	append_string(buf, cdr->SIPSessionID, bufsize);
 	/* SIP IP Address */
 	append_string(buf, cdr->sipIpAddress, bufsize);
 	/* Far End IP Address */
diff --git a/cdr/cdr_manager.c b/cdr/cdr_manager.c
index 081533f3a7..04f9c29a64 100644
--- a/cdr/cdr_manager.c
+++ b/cdr/cdr_manager.c
@@ -325,6 +325,7 @@ static int manager_log(struct ast_cdr *cdr)
 	    "AMAFlags: %s\r\n"
 	    "UniqueID: %s\r\n"
 	    "SessionId: %ld\r\n"
+	    "SIPSessionID: %s\r\n"
 	    "SipIpAddress: %s\r\n"
 	    "farEndIPAddress: %s\r\n"
 	    "sipResponseCode: %ld\r\n"
@@ -360,7 +361,7 @@ static int manager_log(struct ast_cdr *cdr)
 	    cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel,
 	    cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime,
 	    cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition),
-	    ast_channel_amaflags2string(cdr->amaflags), cdr->uniqueid, cdr->sessionId,
+	    ast_channel_amaflags2string(cdr->amaflags), cdr->uniqueid, cdr->sessionId, cdr->SIPSessionID,
 		cdr->sipIpAddress, cdr->farEndIPAddress, cdr->sipResponseCode, cdr->codec, cdr->rtp_stats->localBurstDensity,
 		cdr->rtp_stats->remoteBurstDensity, cdr->rtp_stats->localBurstDuration, cdr->rtp_stats->remoteBurstDuration, cdr->rtp_stats->localGapDensity,
 		cdr->rtp_stats->remoteGapDensity, cdr->rtp_stats->localGapDuration, cdr->rtp_stats->remoteGapDuration, cdr->rtp_stats->localJbRate,
diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c
index 408961d35a..d538084f68 100644
--- a/cdr/cdr_odbc.c
+++ b/cdr/cdr_odbc.c
@@ -154,6 +154,7 @@ static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
 	}
 
 	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sessionId, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->SIPSessionID), 0, cdr->SIPSessionID, 0, NULL);
 	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->sipIpAddress), 0, cdr->sipIpAddress, 0, NULL);
 	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->farEndIPAddress), 0, cdr->farEndIPAddress, 0, NULL);
 	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sipResponseCode, 0, NULL);
diff --git a/cdr/cdr_radius.c b/cdr/cdr_radius.c
index 00b3c1e18d..dbf3f371ca 100644
--- a/cdr/cdr_radius.c
+++ b/cdr/cdr_radius.c
@@ -71,36 +71,37 @@ enum {
 	PW_AST_UNIQUE_ID =    117,
 	PW_AST_USER_FIELD =   118,
 	PW_AST_USER_SESSION_ID =   119,
-	PW_AST_SIP_IP_ADDR =   120,
-	PW_AST_FAR_END_IP_ADDR =   121,
-	PW_AST_SIP_RESPONSE_CODE =   122,
-	PW_AST_CODEC =   123,
-	PW_AST_RTP_LOCAL_BURST_DENSITY =   124,
-	PW_AST_RTP_REMOTE_BURST_DENSITY =   125,
-	PW_AST_RTP_LOCAL_BURST_DURATION =   126,
-	PW_AST_RTP_REMOTE_BURST_DURATION =   127,
-	PW_AST_RTP_LOCAL_GAP_DENSITY =   128,
-	PW_AST_RTP_REMOTE_GAP_DENSITY =   129,
-	PW_AST_RTP_LOCAL_GAP_DURATION =   130,
-	PW_AST_RTP_REMOTE_GAP_DURATION =   131,
-	PW_AST_RTP_LOCAL_JB_RATE =   132,
-	PW_AST_RTP_REMOTE_JB_RATE =   133,
-	PW_AST_RTP_LOCAL_JB_MAX =   134,
-	PW_AST_RTP_REMOTE_JB_MAX =   135,
-	PW_AST_RTP_LOCAL_JB_NOMINAL =   136,
-	PW_AST_RTP_REMOTE_JB_NOMINAL =   137,
-	PW_AST_RTP_LOCAL_JB_ABS_MAX =   138,
-	PW_AST_RTP_REMOTE_JB_ABS_MAX =   139,
-	PW_AST_RTP_JB_AVG =   140,
-	PW_AST_RTP_LOSS_RATE =   141,
-	PW_AST_RTP_DISCARDED =   142,
-	PW_AST_RTP_LOST =   143,
-	PW_AST_RTP_RX_PKTS =   144,
-	PW_AST_RTP_TX_PKTS =   145,
-	PW_AST_RTP_JITTER =   146,
-	PW_AST_RTP_MAX_JITTER =   147,
-	PW_AST_RTP_AVERAGE_ROUND_TRIP_DELAY =   148,
-	PW_AST_RTP_AVERAGE_FAR_END_INTERARRIVAL_JITTER =   149
+	PW_AST_USER_SESSION_ID2 =   120,
+	PW_AST_SIP_IP_ADDR =   121,
+	PW_AST_FAR_END_IP_ADDR =   122,
+	PW_AST_SIP_RESPONSE_CODE =   123,
+	PW_AST_CODEC =   124,
+	PW_AST_RTP_LOCAL_BURST_DENSITY =   125,
+	PW_AST_RTP_REMOTE_BURST_DENSITY =   126,
+	PW_AST_RTP_LOCAL_BURST_DURATION =   127,
+	PW_AST_RTP_REMOTE_BURST_DURATION =   128,
+	PW_AST_RTP_LOCAL_GAP_DENSITY =   129,
+	PW_AST_RTP_REMOTE_GAP_DENSITY =   130,
+	PW_AST_RTP_LOCAL_GAP_DURATION =   131,
+	PW_AST_RTP_REMOTE_GAP_DURATION =   132,
+	PW_AST_RTP_LOCAL_JB_RATE =   133,
+	PW_AST_RTP_REMOTE_JB_RATE =   134,
+	PW_AST_RTP_LOCAL_JB_MAX =   135,
+	PW_AST_RTP_REMOTE_JB_MAX =   136,
+	PW_AST_RTP_LOCAL_JB_NOMINAL =   137,
+	PW_AST_RTP_REMOTE_JB_NOMINAL =   138,
+	PW_AST_RTP_LOCAL_JB_ABS_MAX =   139,
+	PW_AST_RTP_REMOTE_JB_ABS_MAX =   140,
+	PW_AST_RTP_JB_AVG =   141,
+	PW_AST_RTP_LOSS_RATE =   142,
+	PW_AST_RTP_DISCARDED =   143,
+	PW_AST_RTP_LOST =   144,
+	PW_AST_RTP_RX_PKTS =   145,
+	PW_AST_RTP_TX_PKTS =   146,
+	PW_AST_RTP_JITTER =   147,
+	PW_AST_RTP_MAX_JITTER =   148,
+	PW_AST_RTP_AVERAGE_ROUND_TRIP_DELAY =   149,
+	PW_AST_RTP_AVERAGE_FAR_END_INTERARRIVAL_JITTER =   150
 };
 
 enum {
@@ -224,10 +225,14 @@ static int build_radius_record(VALUE_PAIR **tosend, struct ast_cdr *cdr)
 			return -1;
 	}
 
-	/* Session Id */
+	/* SessionId */
 	if (!rc_avpair_add(rh, tosend, PW_AST_USER_SESSION_ID, &cdr->sessionId, 0, VENDOR_CODE))
 		return -1;
 
+	/* SIPSessionID */
+	if (!rc_avpair_add(rh, tosend, PW_AST_USER_SESSION_ID2, &cdr->SIPSessionID, strlen(cdr->SIPSessionID), VENDOR_CODE))
+		return -1;
+
 	/* SIP IP Address */
 	if (!rc_avpair_add(rh, tosend, PW_AST_SIP_IP_ADDR, &cdr->sipIpAddress, strlen(cdr->sipIpAddress), VENDOR_CODE))
 		return -1;
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index 1b98e55635..ffdeaddb6b 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -350,6 +350,8 @@ struct ast_cdr {
 	int sequence;
 	/*! SessionId */
 	int sessionId;
+	/*! SIPSessionID */
+	char SIPSessionID[33];
 	/*! sipIpAddress */
 	char sipIpAddress[40];
 	/*! farEndIPAddress */
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 2e0fba024d..280a5cb263 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -4402,6 +4402,8 @@ enum ast_channel_state ast_channel_state(const struct ast_channel *chan);
 ast_callid ast_channel_callid(const struct ast_channel *chan);
 unsigned int ast_channel_sessionId(const struct ast_channel *chan);
 void ast_channel_sessionId_set(struct ast_channel *chan, unsigned int value);
+const char *ast_channel_SIPSessionID(const struct ast_channel *chan);
+void ast_channel_SIPSessionID_set(struct ast_channel *chan, const char *value, size_t size);
 const char *ast_channel_sipIpAddress(const struct ast_channel *chan);
 void ast_channel_sipIpAddress_set(struct ast_channel *chan, const char *value, size_t size);
 const char *ast_channel_farEndIPAddress(const struct ast_channel *chan);
diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h
index 0d0875ce89..d5bcf01adf 100644
--- a/include/asterisk/stasis_channels.h
+++ b/include/asterisk/stasis_channels.h
@@ -156,7 +156,8 @@ struct ast_channel_snapshot {
 	struct ast_flags softhangup_flags;                /*!< softhangup channel flags */
 	struct varshead *manager_vars;                    /*!< Variables to be appended to manager events */
 	struct varshead *ari_vars;                        /*!< Variables to be appended to ARI events */
-	unsigned int sessionId;                           /*!< Session Id */
+	unsigned int sessionId;                           /*!< SessionId */
+	char SIPSessionID[33];				  /*!< Session-ID */
 	char sipIpAddress[40];                            /*!< SIP IP Address */
 	char farEndIPAddress[40];                         /*!< Far End IP Address */
 	unsigned int sipResponseCode;                     /*!< SIP Response Code for Invite */
diff --git a/main/cdr.c b/main/cdr.c
index 941031c14c..7120708b6b 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -732,10 +732,11 @@ struct cdr_object {
 		AST_STRING_FIELD(exten);            /*!< The accepted extension for Party A */
 		AST_STRING_FIELD(party_b_name);     /*!< Party B channel name. Cached here as it is the all CDRs container key */
 		AST_STRING_FIELD(sipIpAddress);     /*!< SIP IP Address */
+		AST_STRING_FIELD(SIPSessionID);	    /*!< SIPSessionID */
 		AST_STRING_FIELD(farEndIPAddress);  /*!< Far End IP Address */
 		AST_STRING_FIELD(codec);     	    /*!< Codec used */
 	);
-	unsigned int sessionId;                 /*!< Session Id */
+	unsigned int sessionId;                 /*!< SessionId */
 	unsigned int sipResponseCode;           /*!< Sip Response Code on Invite */
 	cdr_rtp_statistics *rtp_stats;          /*!< RTP Statistics */
 	struct cdr_object *next;                /*!< The next CDR object in the chain */
@@ -1333,6 +1334,10 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 		if (party_a->sessionId)
 			cdr_copy->sessionId = party_a->sessionId;
 
+		if (ast_strlen_zero(cdr_copy->SIPSessionID) && !ast_strlen_zero(party_a->SIPSessionID)) {
+			ast_copy_string(cdr_copy->SIPSessionID, party_a->SIPSessionID, sizeof(cdr_copy->SIPSessionID));
+		}
+
 		if (ast_strlen_zero(cdr_copy->sipIpAddress) && !ast_strlen_zero(party_a->sipIpAddress)) {
 			ast_copy_string(cdr_copy->sipIpAddress, party_a->sipIpAddress, sizeof(cdr_copy->sipIpAddress));
 		}
@@ -1362,6 +1367,10 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 			if (party_b->sessionId)
 				cdr_copy->sessionId = party_b->sessionId;
 
+			if (ast_strlen_zero(cdr_copy->SIPSessionID) && !ast_strlen_zero(party_b->SIPSessionID)) {
+				ast_copy_string(cdr_copy->SIPSessionID, party_b->SIPSessionID, sizeof(cdr_copy->SIPSessionID));
+			}
+
 			if (ast_strlen_zero(cdr_copy->sipIpAddress) && !ast_strlen_zero(party_b->sipIpAddress)) {
 				ast_copy_string(cdr_copy->sipIpAddress, party_b->sipIpAddress, sizeof(cdr_copy->sipIpAddress));
 			}
@@ -3166,6 +3175,8 @@ void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char
 		ast_copy_string(workspace, varbuf, workspacelen);
 	} else if (!strcasecmp(name, "sessionId")) {
 		snprintf(workspace, workspacelen, "%ld", cdr->sessionId);
+	} else if (!strcasecmp(name, "SIPSessionID")) {
+		ast_copy_string(workspace, cdr->SIPSessionID, workspacelen);
 	} else if (!strcasecmp(name, "sipIpAddress")) {
 		ast_copy_string(workspace, cdr->sipIpAddress, workspacelen);
 	} else if (!strcasecmp(name, "farEndIPAddress")) {
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index 1b3ebda9bb..c42330e951 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -223,6 +223,7 @@ struct ast_channel {
 	struct ast_channel_snapshot *snapshot; /*!< The current up to date snapshot of the channel */
 	struct ast_flags snapshot_segment_flags; /*!< Flags regarding the segments of the snapshot */
 	unsigned int sessionId; /*!< Session Id from SDP for channel */
+	char SIPSessionID[33]; /* SIPSessionID from  Session-ID header */
 	char sipIpAddress[40];  /*!< local IP address that sip client binds to */
 	char farEndIPAddress[40];  /*!< Far End IP Address */
 	unsigned int sipResponseCode; /*!< SIP response Code */
@@ -808,6 +809,16 @@ void ast_channel_sessionId_set(struct ast_channel *chan, unsigned int value)
 {
 	chan->sessionId = value;
 }
+
+const char *ast_channel_SIPSessionID(const struct ast_channel *chan)
+{
+	return chan->SIPSessionID;
+}
+void ast_channel_SIPSessionID_set(struct ast_channel *chan, const char *value, size_t size)
+{
+	ast_copy_string(chan->SIPSessionID, value, size);
+}
+
 const char *ast_channel_sipIpAddress(const struct ast_channel *chan)
 {
 	return chan->sipIpAddress;
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index 3cf6ff4d33..4efec90e32 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -552,6 +552,7 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
 	snapshot->manager_vars = ast_channel_get_manager_vars(chan);
 	snapshot->ari_vars = ast_channel_get_ari_vars(chan);
 	snapshot->sessionId = ast_channel_sessionId(chan);
+	ast_copy_string(snapshot->SIPSessionID, ast_channel_SIPSessionID(chan), sizeof(snapshot->SIPSessionID));
 	ast_copy_string(snapshot->sipIpAddress, ast_channel_sipIpAddress(chan), sizeof(snapshot->sipIpAddress));
 	ast_copy_string(snapshot->farEndIPAddress, ast_channel_farEndIPAddress(chan), sizeof(snapshot->farEndIPAddress));
 	snapshot->sipResponseCode = ast_channel_sipResponseCode(chan);
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index ce35e6fa44..1ad93b7277 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -4117,6 +4117,14 @@ static int new_invite(struct new_invite *invite)
 
 end:
 	if (invite->session && invite->session->channel) {
+		pjsip_generic_string_hdr *SessionID = NULL;
+		static const pj_str_t headerName = { "Session-ID", 10 };
+		SessionID = pjsip_msg_find_hdr_by_name(invite->rdata->msg_info.msg, &headerName, NULL);
+		char value[33] = {0};
+		if (SessionID)
+			ast_copy_pj_str(&value, &SessionID->hvalue, pj_strlen(&SessionID->hvalue) + 1);
+
+		ast_channel_SIPSessionID_set(invite->session->channel, value, 33);
 		ast_channel_sessionId_set(invite->session->channel, local->origin.id);
 		ast_channel_sipIpAddress_set(invite->session->channel, pj_strbuf(&local->origin.addr), pj_strlen(&local->origin.addr));
 	}
@@ -4563,8 +4571,19 @@ static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_d
 			supplement->incoming_response(session, rdata);
 		}
 	}
-	if (session && session->channel)
+	if (session && session->channel) {
 		ast_channel_sipResponseCode_set(session->channel, status.code == 180 ? 487 : status.code);
+		if (status.code == 200) {
+			pjsip_generic_string_hdr *SessionID = NULL;
+			static const pj_str_t headerName = { "Session-ID", 10 };
+			SessionID = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &headerName, NULL);
+			char value[33] = {0};
+			if (SessionID)
+				ast_copy_pj_str(&value, &SessionID->hvalue, pj_strlen(&SessionID->hvalue) + 1);
+
+			ast_channel_SIPSessionID_set(session->channel, value, 33);
+		}
+	}
 
 	SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
 }
-- 
GitLab