Asterisk - The Open Source Telephony Project  21.4.1
res_pjsip_stir_shaken.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2020, Sangoma Technologies Corporation
5  *
6  * Ben Ford <bford@sangoma.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*** MODULEINFO
20  <depend>pjproject</depend>
21  <depend>res_pjsip</depend>
22  <depend>res_pjsip_session</depend>
23  <depend>res_stir_shaken</depend>
24  <support_level>core</support_level>
25  ***/
26 
27 #include "asterisk.h"
28 
29 #define _TRACE_PREFIX_ "pjss",__LINE__, ""
30 
31 #include "asterisk/callerid.h"
32 #include "asterisk/res_pjsip.h"
33 #include "asterisk/res_pjsip_session.h"
34 #include "asterisk/module.h"
35 #include "asterisk/rtp_engine.h"
36 
37 #include "asterisk/res_stir_shaken.h"
38 
39 static const pj_str_t identity_hdr_str = { "Identity", 8 };
40 static const pj_str_t date_hdr_str = { "Date", 4 };
41 
42 /* Response codes from RFC8224 */
43 enum sip_response_code {
44  SIP_RESPONSE_CODE_OK = 200,
45  SIP_RESPONSE_CODE_STALE_DATE = 403,
46  SIP_RESPONSE_CODE_USE_IDENTITY_HEADER = 428,
47  SIP_RESPONSE_CODE_BAD_IDENTITY_INFO = 436,
48  SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL = 437,
49  SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER = 438,
50  SIP_RESPONSE_CODE_USE_SUPPORTED_PASSPORT_FORMAT = 428,
51  SIP_RESPONSE_CODE_INTERNAL_ERROR = 500,
52 };
53 
54 #define SIP_RESPONSE_CODE_OK_STR "OK"
55 /* Response strings from RFC8224 */
56 #define SIP_RESPONSE_CODE_STALE_DATE_STR "Stale Date"
57 #define SIP_RESPONSE_CODE_USE_IDENTITY_HEADER_STR "Use Identity Header"
58 #define SIP_RESPONSE_CODE_USE_SUPPORTED_PASSPORT_FORMAT_STR "Use Supported PASSporT Format"
59 #define SIP_RESPONSE_CODE_BAD_IDENTITY_INFO_STR "Bad Identity Info"
60 #define SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL_STR "Unsupported Credential"
61 #define SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER_STR "Invalid Identity Header"
62 #define SIP_RESPONSE_CODE_INTERNAL_ERROR_STR "Internal Error"
63 
64 #define response_to_str(_code) \
65 case _code: \
66  return _code ## _STR;
67 
68 static const char *sip_response_code_to_str(enum sip_response_code code)
69 {
70  switch (code) {
71  response_to_str(SIP_RESPONSE_CODE_OK)
72  response_to_str(SIP_RESPONSE_CODE_STALE_DATE)
73  response_to_str(SIP_RESPONSE_CODE_USE_IDENTITY_HEADER)
74  response_to_str(SIP_RESPONSE_CODE_BAD_IDENTITY_INFO)
75  response_to_str(SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL)
76  response_to_str(SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER)
77  default:
78  break;
79  }
80  return "";
81 }
82 
83 #define translate_code(_vs_rc, _sip_rc) \
84 case AST_STIR_SHAKEN_VS_ ## _vs_rc: \
85  return SIP_RESPONSE_CODE_ ## _sip_rc;
86 
87 static enum sip_response_code vs_code_to_sip_code(
88  enum ast_stir_shaken_vs_response_code vs_rc)
89 {
90  /*
91  * We want to use a switch/case statement here because
92  * it'll spit out an error if VS codes are added to the
93  * enum but aren't present here.
94  */
95  switch (vs_rc) {
96  translate_code(SUCCESS, OK)
97  translate_code(DISABLED, OK)
98  translate_code(INVALID_ARGUMENTS, INTERNAL_ERROR)
99  translate_code(INTERNAL_ERROR, INTERNAL_ERROR)
100  translate_code(NO_IDENTITY_HDR, USE_IDENTITY_HEADER)
101  translate_code(NO_DATE_HDR, STALE_DATE)
102  translate_code(DATE_HDR_PARSE_FAILURE, STALE_DATE)
103  translate_code(DATE_HDR_EXPIRED, STALE_DATE)
104  translate_code(NO_JWT_HDR, INVALID_IDENTITY_HEADER)
105  translate_code(INVALID_OR_NO_X5U, INVALID_IDENTITY_HEADER)
106  translate_code(CERT_CACHE_MISS, INVALID_IDENTITY_HEADER)
107  translate_code(CERT_CACHE_INVALID, INVALID_IDENTITY_HEADER)
108  translate_code(CERT_CACHE_EXPIRED, INVALID_IDENTITY_HEADER)
109  translate_code(CERT_RETRIEVAL_FAILURE, BAD_IDENTITY_INFO)
110  translate_code(CERT_CONTENTS_INVALID, UNSUPPORTED_CREDENTIAL)
111  translate_code(CERT_NOT_TRUSTED, UNSUPPORTED_CREDENTIAL)
112  translate_code(CERT_DATE_INVALID, UNSUPPORTED_CREDENTIAL)
113  translate_code(CERT_NO_TN_AUTH_EXT, UNSUPPORTED_CREDENTIAL)
114  translate_code(CERT_NO_SPC_IN_TN_AUTH_EXT, UNSUPPORTED_CREDENTIAL)
115  translate_code(NO_RAW_KEY, UNSUPPORTED_CREDENTIAL)
116  translate_code(SIGNATURE_VALIDATION, INVALID_IDENTITY_HEADER)
117  translate_code(NO_IAT, INVALID_IDENTITY_HEADER)
118  translate_code(IAT_EXPIRED, STALE_DATE)
119  translate_code(INVALID_OR_NO_PPT, INVALID_IDENTITY_HEADER)
120  translate_code(INVALID_OR_NO_ALG, INVALID_IDENTITY_HEADER)
121  translate_code(INVALID_OR_NO_TYP, INVALID_IDENTITY_HEADER)
122  translate_code(INVALID_OR_NO_ATTEST, INVALID_IDENTITY_HEADER)
123  translate_code(NO_ORIGID, INVALID_IDENTITY_HEADER)
124  translate_code(NO_ORIG_TN, INVALID_IDENTITY_HEADER)
125  translate_code(NO_DEST_TN, INVALID_IDENTITY_HEADER)
126  translate_code(INVALID_HEADER, INVALID_IDENTITY_HEADER)
127  translate_code(INVALID_GRANT, INVALID_IDENTITY_HEADER)
128  translate_code(INVALID_OR_NO_GRANTS, INVALID_IDENTITY_HEADER)
129  translate_code(CID_ORIG_TN_MISMATCH, INVALID_IDENTITY_HEADER)
130  translate_code(RESPONSE_CODE_MAX, INVALID_IDENTITY_HEADER)
131  }
132 
133  return 500;
134 }
135 
136 enum process_failure_rc {
137  PROCESS_FAILURE_CONTINUE = 0,
138  PROCESS_FAILURE_REJECT,
139  PROCESS_FAILURE_SYSTEM_FAILURE,
140 };
141 
142 static void reject_incoming_call(struct ast_sip_session *session,
143  enum sip_response_code response_code)
144 {
145  ast_sip_session_terminate(session, response_code);
146  ast_hangup(session->channel);
147 }
148 
149 static enum process_failure_rc process_failure(struct ast_stir_shaken_vs_ctx *ctx,
150  const char *caller_id, struct ast_sip_session *session,
151  pjsip_rx_data *rdata, enum ast_stir_shaken_vs_response_code vs_rc)
152 {
153  enum sip_response_code response_code = vs_code_to_sip_code(vs_rc);
154  pj_str_t response_str;
155  const char *response_string =
156  sip_response_code_to_str(response_code);
157  enum stir_shaken_failure_action_enum failure_action =
158  ast_stir_shaken_vs_get_failure_action(ctx);
159  const char *tag = ast_sip_session_get_name(session);
160  SCOPE_ENTER(1, "%s: FA: %d RC: %d\n", tag,
161  failure_action, response_code);
162 
163  pj_cstr(&response_str, response_string);
164 
165  if (failure_action == stir_shaken_failure_action_REJECT_REQUEST) {
166  reject_incoming_call(session, response_code);
167  SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_REJECT,
168  "%s: Rejecting request and terminating session\n",
169  tag);
170  }
171 
172  ast_stir_shaken_vs_ctx_set_response_code(ctx, vs_rc);
173  ast_stir_shaken_add_result_to_channel(ctx);
174 
175  if (failure_action == stir_shaken_failure_action_CONTINUE_RETURN_REASON) {
176  int rc = ast_sip_session_add_reason_header(session,
177  ast_stir_shaken_vs_get_use_rfc9410_responses(ctx) ? "STIR" : "SIP",
178  response_code, response_str.ptr);
179  if (rc != 0) {
180  SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_SYSTEM_FAILURE,
181  "%s: Failed to add Reason header\n", tag);
182  }
183  SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_CONTINUE,
184  "%s: Attaching reason code to session\n", tag);
185  }
186  SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_CONTINUE,
187  "%s: Continuing\n", tag);
188 }
189 
190 /*!
191  * \internal
192  * \brief Session supplement callback on an incoming INVITE request
193  *
194  * When we receive an INVITE, check it for STIR/SHAKEN information and
195  * decide what to do from there
196  *
197  * \param session The session that has received an INVITE
198  * \param rdata The incoming INVITE
199  */
200 static int stir_shaken_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
201 {
202  RAII_VAR(struct ast_stir_shaken_vs_ctx *, ctx, NULL, ao2_cleanup);
203  RAII_VAR(char *, header, NULL, ast_free);
204  RAII_VAR(char *, payload, NULL, ast_free);
205  char *identity_hdr_val;
206  char *date_hdr_val;
207  char *caller_id = session->id.number.str;
208  const char *session_name = ast_sip_session_get_name(session);
209  struct ast_channel *chan = session->channel;
210  enum ast_stir_shaken_vs_response_code vs_rc;
211  enum process_failure_rc p_rc;
212  SCOPE_ENTER(1, "%s: Enter\n", session_name);
213 
214  if (!session) {
215  SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "No session\n");
216  }
217  if (!session->channel) {
218  SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No channel\n", session_name);
219  }
220  if (!rdata) {
221  SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No rdata\n", session_name);
222  }
223 
224  /* Check if this is a reinvite. If it is, we don't need to do anything */
225  if (rdata->msg_info.to->tag.slen) {
226  SCOPE_EXIT_RTN_VALUE(0, "%s: Reinvite. No action needed\n", session_name);
227  }
228 
229  /*
230  * Shortcut: If there's no callerid or profile name,
231  * just bail now.
232  */
233  if (ast_strlen_zero(caller_id)
234  || ast_strlen_zero(session->endpoint->stir_shaken_profile)) {
235  SCOPE_EXIT_RTN_VALUE(0, "%s: No callerid or profile name. No action needed\n", session_name);
236  }
237 
238  vs_rc = ast_stir_shaken_vs_ctx_create(caller_id, chan,
239  session->endpoint->stir_shaken_profile,
240  session_name, &ctx);
241  if (vs_rc == AST_STIR_SHAKEN_VS_DISABLED) {
242  SCOPE_EXIT_RTN_VALUE(0, "%s: VS Disabled\n", session_name);
243  } else if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
244  reject_incoming_call(session, 500);
245  SCOPE_EXIT_RTN_VALUE(1, "%s: Unable to create context. Call terminated\n",
246  session_name);
247  }
248 
249  identity_hdr_val = ast_sip_rdata_get_header_value(rdata, identity_hdr_str);
250  if (ast_strlen_zero(identity_hdr_val)) {
251  p_rc = process_failure(ctx, caller_id, session, rdata,
252  AST_STIR_SHAKEN_VS_NO_IDENTITY_HDR);
253  if (p_rc == PROCESS_FAILURE_CONTINUE) {
254  SCOPE_EXIT_RTN_VALUE(0, "%s: No Identity header found. Call continuing\n",
255  session_name);
256  }
257  SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No Identity header found. Call terminated\n",
258  session_name);
259  }
260 
261  vs_rc = ast_stir_shaken_vs_ctx_add_identity_hdr(ctx, identity_hdr_val);
262  if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
263  reject_incoming_call(session, 500);
264  SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: Unable to add Identity header. Call terminated.\n",
265  session_name);
266  }
267 
268  date_hdr_val = ast_sip_rdata_get_header_value(rdata, date_hdr_str);
269  if (ast_strlen_zero(date_hdr_val)) {
270  p_rc = process_failure(ctx, caller_id, session, rdata,
271  AST_STIR_SHAKEN_VS_NO_DATE_HDR);
272  if (p_rc == PROCESS_FAILURE_CONTINUE) {
273  SCOPE_EXIT_RTN_VALUE(0, "%s: No Date header found. Call continuing\n",
274  session_name);
275  }
276  SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No Date header found. Call terminated\n",
277  session_name);
278  }
279 
280  ast_stir_shaken_vs_ctx_add_date_hdr(ctx, date_hdr_val);
281  if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
282  reject_incoming_call(session, 500);
283  SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: Unable to add Date header. Call terminated.\n",
284  session_name);
285  }
286 
287  vs_rc = ast_stir_shaken_vs_verify(ctx);
288  if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
289  p_rc = process_failure(ctx, caller_id, session, rdata, vs_rc);
290  if (p_rc == PROCESS_FAILURE_CONTINUE) {
291  SCOPE_EXIT_RTN_VALUE(0, "%s: Verification failed. Call continuing\n",
292  session_name);
293  }
294  SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: Verification failed. Call terminated\n",
295  session_name);
296 
297  }
298 
299  ast_stir_shaken_add_result_to_channel(ctx);
300 
301  SCOPE_EXIT_RTN_VALUE(0, "Passed\n");
302 }
303 
304 static void add_fingerprints_if_present(struct ast_sip_session *session,
305  struct ast_stir_shaken_as_ctx *ctx)
306 {
307  struct ast_sip_session_media_state *ms = session->pending_media_state;
308  struct ast_sip_session_media *m = NULL;
309  struct ast_rtp_engine_dtls *d = NULL;
310  enum ast_rtp_dtls_hash h;
311  int i;
312  const char *tag = ast_sip_session_get_name(session);
313  size_t count = AST_VECTOR_SIZE(&ms->sessions);
314  SCOPE_ENTER(4, "%s: Check %zu media sessions for fingerprints\n",
315  tag, count);
316 
317  if (!ast_stir_shaken_as_ctx_wants_fingerprints(ctx)) {
318  SCOPE_EXIT_RTN("%s: Fingerprints not needed\n", tag);
319  }
320 
321  for (i = 0; i < count; i++) {
322  const char *f;
323 
324  m = AST_VECTOR_GET(&ms->sessions, i);
325  if (!m|| !m->rtp) {
326  ast_trace(1, "Session: %d: No session or rtp instance\n", i);
327  continue;
328  }
330  h = d->get_fingerprint_hash(m->rtp);
331  f = d->get_fingerprint(m->rtp);
332 
333  ast_stir_shaken_as_ctx_add_fingerprint(ctx,
334  h == AST_RTP_DTLS_HASH_SHA256 ? "sha-256" : "sha-1", f);
335  }
336  SCOPE_EXIT_RTN("%s: Done\n", tag);
337 }
338 
339 static char *get_dest_tn(pjsip_tx_data *tdata, const char *tag)
340 {
341  pjsip_fromto_hdr *to;
342  pjsip_sip_uri *uri;
343  char *dest_tn = NULL;
344  SCOPE_ENTER(4, "%s: Enter\n", tag);
345 
346  to = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);
347  if (!to) {
348  SCOPE_EXIT_RTN_VALUE(NULL, "%s: Failed to find To header\n", tag);
349  }
350 
351  uri = pjsip_uri_get_uri(to->uri);
352  if (!uri) {
353  SCOPE_EXIT_RTN_VALUE(NULL,
354  "%s: Failed to retrieve URI from To header\n", tag);
355  }
356 
357  dest_tn = ast_malloc(uri->user.slen + 1);
358  if (!dest_tn) {
359  SCOPE_EXIT_RTN_VALUE(NULL,
360  "%s: Failed to allocate memory for dest_tn\n", tag);
361  }
362 
363  ast_copy_pj_str(dest_tn, &uri->user, uri->user.slen + 1);
364 
365  SCOPE_EXIT_RTN_VALUE(dest_tn, "%s: Done\n", tag);
366 }
367 
368 static void add_date_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)
369 {
370  pjsip_fromto_hdr *old_date;
371  const char *session_name = ast_sip_session_get_name(session);
372  SCOPE_ENTER(1, "%s: Enter\n", session_name);
373 
374  old_date = pjsip_msg_find_hdr_by_name(tdata->msg, &date_hdr_str, NULL);
375  if (old_date) {
376  SCOPE_EXIT_RTN("Found existing Date header, no need to add one\n");
377  }
378 
379  ast_sip_add_date_header(tdata);
380  SCOPE_EXIT_RTN("Done\n");
381 }
382 
383 static void stir_shaken_outgoing_request(struct ast_sip_session *session,
384  pjsip_tx_data *tdata)
385 {
386  struct ast_party_id effective_id;
387  struct ast_party_id connected_id;
388  pjsip_generic_string_hdr *old_identity;
389  pjsip_generic_string_hdr *identity_hdr;
390  pj_str_t identity_val;
391  char *dest_tn;
392  char *identity_str;
393  struct ast_stir_shaken_as_ctx *ctx = NULL;
394  enum ast_stir_shaken_as_response_code as_rc;
395  const char *session_name = ast_sip_session_get_name(session);
396  SCOPE_ENTER(1, "%s: Enter\n", session_name);
397 
398  if (!session) {
399  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "No session\n");
400  }
401  if (!session->channel) {
402  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: No channel\n", session_name);
403  }
404  if (!tdata) {
405  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: No tdata\n", session_name);
406  }
407 
408  old_identity = pjsip_msg_find_hdr_by_name(tdata->msg, &identity_hdr_str, NULL);
409  if (old_identity) {
410  SCOPE_EXIT_RTN("Found an existing Identity header\n");
411  }
412 
413  dest_tn = get_dest_tn(tdata, session_name);
414  if (!dest_tn) {
415  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to find destination tn\n",
416  session_name);
417  }
418 
419  ast_party_id_init(&connected_id);
420  ast_channel_lock(session->channel);
421  effective_id = ast_channel_connected_effective_id(session->channel);
422  ast_party_id_copy(&connected_id, &effective_id);
423  ast_channel_unlock(session->channel);
424 
425  if (!ast_sip_can_present_connected_id(session, &connected_id)) {
426  ast_free(dest_tn);
427  ast_party_id_free(&connected_id);
428  SCOPE_EXIT_RTN("Unable to get caller id\n");
429  }
430 
431  as_rc = ast_stir_shaken_as_ctx_create(connected_id.number.str,
432  dest_tn, session->channel,
433  session->endpoint->stir_shaken_profile,
434  session_name, &ctx);
435 
436  ast_free(dest_tn);
437  ast_party_id_free(&connected_id);
438 
439  if (as_rc == AST_STIR_SHAKEN_AS_DISABLED) {
440  SCOPE_EXIT_RTN("%s: AS Disabled\n", session_name);
441  } else if (as_rc != AST_STIR_SHAKEN_AS_SUCCESS) {
442  SCOPE_EXIT_RTN("%s: Unable to create context\n",
443  session_name);
444  }
445 
446  add_date_header(session, tdata);
447  add_fingerprints_if_present(session, ctx);
448 
449  as_rc = ast_stir_shaken_attest(ctx, &identity_str);
450  if (as_rc != AST_STIR_SHAKEN_AS_SUCCESS) {
451  ao2_cleanup(ctx);
452  SCOPE_EXIT_LOG(LOG_ERROR,
453  "%s: Failed to create attestation\n", session_name);
454  }
455 
456  ast_trace(1, "%s: Identity header: %s\n", session_name, identity_str);
457  identity_val = pj_str(identity_str);
458  identity_hdr = pjsip_generic_string_hdr_create(tdata->pool, &identity_hdr_str, &identity_val);
459  ast_free(identity_str);
460  if (!identity_hdr) {
461  ao2_cleanup(ctx);
462  SCOPE_EXIT_LOG_RTN(LOG_ERROR,
463  "%s: Unable to create Identity header\n", session_name);
464  }
465 
466  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)identity_hdr);
467 
468  ao2_cleanup(ctx);
469  SCOPE_EXIT_RTN("Done\n");
470 }
471 
472 static struct ast_sip_session_supplement stir_shaken_supplement = {
473  .method = "INVITE",
474  .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1, /* Run AFTER channel creation */
475  .incoming_request = stir_shaken_incoming_request,
476  .outgoing_request = stir_shaken_outgoing_request,
477 };
478 
479 static int unload_module(void)
480 {
481  ast_sip_session_unregister_supplement(&stir_shaken_supplement);
482  return 0;
483 }
484 
485 static int load_module(void)
486 {
487  ast_sip_session_register_supplement(&stir_shaken_supplement);
489 }
490 
491 #undef AST_BUILDOPT_SUM
492 #define AST_BUILDOPT_SUM ""
493 
494 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP STIR/SHAKEN Module for Asterisk",
495  .support_level = AST_MODULE_SUPPORT_CORE,
496  .load = load_module,
497  .unload = unload_module,
498  .load_pri = AST_MODPRI_DEFAULT,
499  .requires = "res_pjsip,res_pjsip_session,res_stir_shaken",
500 );
Information needed to identify an endpoint in a call.
Definition: channel.h:338
Main Channel structure associated with a channel.
struct ast_sip_endpoint * endpoint
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
Asterisk main include file. File version handling, generic pbx functions.
Structure which contains media state information (streams, sessions)
struct ast_sip_session_media_state * pending_media_state
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
const char *(* get_fingerprint)(struct ast_rtp_instance *instance)
Definition: rtp_engine.h:641
void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
Copy the source party id information to the destination party id.
Definition: channel.c:1765
#define SCOPE_EXIT_LOG(__log_level,...)
void ast_party_id_free(struct ast_party_id *doomed)
Destroy the party id contents.
Definition: channel.c:1811
A structure describing a SIP session.
enum ast_rtp_dtls_hash(* get_fingerprint_hash)(struct ast_rtp_instance *instance)
Definition: rtp_engine.h:639
struct ast_channel * channel
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
struct ast_sip_session_media_state::@267 sessions
Mapping of stream to media sessions.
Structure that represents the optional DTLS SRTP support within an RTP engine.
Definition: rtp_engine.h:621
struct ast_rtp_engine_dtls * ast_rtp_instance_get_dtls(struct ast_rtp_instance *instance)
Obtain a pointer to the DTLS support present on an RTP instance.
Definition: rtp_engine.c:3159
ast_rtp_dtls_hash
DTLS fingerprint hashes.
Definition: rtp_engine.h:578
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
void ast_party_id_init(struct ast_party_id *init)
Initialize the given party id structure.
Definition: channel.c:1757
A structure containing SIP session media information.
const ast_string_field stir_shaken_profile
Definition: res_pjsip.h:976
A supplement to SIP message processing.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
struct ast_rtp_instance * rtp
RTP instance itself.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Pluggable RTP Architecture.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
struct ast_party_id id
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342