Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
Data Structures | Functions | Variables
redirect.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include "asterisk/linkedlists.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_redirect.h"
Include dependency graph for redirect.c:

Go to the source code of this file.

Data Structures

struct  ast_sip_redirect_state
 Redirect state structure. More...
 
struct  redirect_contact
 
struct  redirect_contact_list
 List of redirect contacts. More...
 
struct  redirect_method_map
 Mapping of SIP method names to their corresponding redirect flags. More...
 
struct  visited_uri
 

Functions

static int add_visited_uri (struct ast_sip_redirect_state *state, const char *uri)
 
int ast_sip_redirect_check_loop (const struct ast_sip_redirect_state *state, const char *uri)
 Check if a URI would create a redirect loop.
 
struct ast_sip_endpointast_sip_redirect_get_endpoint (const struct ast_sip_redirect_state *state)
 Get the endpoint from the redirect state.
 
int ast_sip_redirect_get_hop_count (const struct ast_sip_redirect_state *state)
 Get the current hop count.
 
int ast_sip_redirect_get_next_uri (struct ast_sip_redirect_state *state, char **uri_out)
 Get the next redirect URI to try.
 
int ast_sip_redirect_parse_3xx (pjsip_rx_data *rdata, struct ast_sip_redirect_state *state)
 Parse a 3xx redirect response and extract contacts.
 
struct ast_sip_redirect_stateast_sip_redirect_state_create (struct ast_sip_endpoint *endpoint, const char *initial_uri)
 Create a new redirect state.
 
void ast_sip_redirect_state_destroy (struct ast_sip_redirect_state *state)
 Destroy a redirect state and free all resources.
 
int ast_sip_should_redirect (struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 Check if redirect should be followed based on endpoint configuration.
 
static float extract_q_value (const pjsip_contact_hdr *contact)
 
static void insert_contact_sorted (struct redirect_contact_list *list, struct redirect_contact *new_contact)
 
static int is_uri_visited (const struct ast_sip_redirect_state *state, const char *uri)
 
static int method_allowed_for_redirect (struct ast_sip_endpoint *endpoint, const pj_str_t *method_name)
 
static int parse_redirect_contacts (pjsip_rx_data *rdata, struct redirect_contact_list *contacts, const struct ast_sip_redirect_state *state)
 

Variables

static const struct redirect_method_map redirect_methods []
 

Function Documentation

◆ add_visited_uri()

static int add_visited_uri ( struct ast_sip_redirect_state state,
const char *  uri 
)
static

Definition at line 190 of file redirect.c.

191{
192 struct visited_uri *visited;
193
194 visited = ast_calloc(1, sizeof(*visited));
195 if (!visited) {
196 return -1;
197 }
198
199 ast_copy_string(visited->uri, uri, sizeof(visited->uri));
200 AST_LIST_INSERT_TAIL(&state->visited_uris, visited, list);
201
202 return 0;
203}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
struct visited_uri::@495 list
char uri[PJSIP_MAX_URL_SIZE]
Definition redirect.c:32

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_TAIL, visited_uri::list, and visited_uri::uri.

Referenced by ast_sip_redirect_get_next_uri().

◆ ast_sip_redirect_check_loop()

int ast_sip_redirect_check_loop ( const struct ast_sip_redirect_state state,
const char *  uri 
)

Check if a URI would create a redirect loop.

Parameters
stateThe redirect state
uriThe URI to check
Return values
0if URI is safe (not visited)
1if URI would create a loop (already visited)

Definition at line 429 of file redirect.c.

430{
431 return is_uri_visited(state, uri);
432}
static int is_uri_visited(const struct ast_sip_redirect_state *state, const char *uri)
Definition redirect.c:174

References is_uri_visited(), and redirect_contact::uri.

◆ ast_sip_redirect_get_endpoint()

struct ast_sip_endpoint * ast_sip_redirect_get_endpoint ( const struct ast_sip_redirect_state state)

Get the endpoint from the redirect state.

Parameters
stateThe redirect state
Returns
The endpoint (borrowed reference, do not cleanup)

Definition at line 439 of file redirect.c.

440{
441 return state->endpoint;
442}

Referenced by handle_message_redirect(), msg_response_callback(), and send_message_to_uri().

◆ ast_sip_redirect_get_hop_count()

int ast_sip_redirect_get_hop_count ( const struct ast_sip_redirect_state state)

Get the current hop count.

Parameters
stateThe redirect state
Returns
The current hop count

Definition at line 434 of file redirect.c.

435{
436 return state->hop_count;
437}

Referenced by handle_message_redirect(), and send_message_to_uri().

◆ ast_sip_redirect_get_next_uri()

int ast_sip_redirect_get_next_uri ( struct ast_sip_redirect_state state,
char **  uri_out 
)

Get the next redirect URI to try.

This function returns the next contact URI from the redirect response, ordered by q-value (highest first). It also marks the URI as visited to prevent loops on subsequent redirects.

Parameters
stateThe redirect state
uri_outPointer to store the URI string (caller must free)
Return values
-1if no more URIs available
0on success
Note
The caller must ast_free() the returned URI string

Definition at line 398 of file redirect.c.

399{
400 struct redirect_contact *contact;
401
402 if (!uri_out) {
403 return -1;
404 }
405
406 /* Get the first contact from the pending list */
407 contact = AST_LIST_REMOVE_HEAD(&state->pending_contacts, list);
408 if (!contact) {
409 return -1;
410 }
411
412 /* Allocate and return the URI string */
413 *uri_out = ast_strdup(contact->uri);
414 if (!*uri_out) {
415 ast_free(contact);
416 return -1;
417 }
418
419 /* Add to visited list to prevent loops */
420 if (add_visited_uri(state, contact->uri)) {
421 ast_log(LOG_WARNING, "Failed to add URI to visited list for endpoint '%s'. Loop detection may be impaired.\n",
423 }
424
425 ast_free(contact);
426 return 0;
427}
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_log
Definition astobj2.c:42
#define LOG_WARNING
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
static int add_visited_uri(struct ast_sip_redirect_state *state, const char *uri)
Definition redirect.c:190
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
char uri[PJSIP_MAX_URL_SIZE]
Definition redirect.c:41
struct redirect_contact::@496 list

References add_visited_uri(), ast_free, AST_LIST_REMOVE_HEAD, ast_log, ast_sorcery_object_get_id(), ast_strdup, redirect_contact::list, LOG_WARNING, and redirect_contact::uri.

Referenced by handle_message_redirect(), and msg_response_callback().

◆ ast_sip_redirect_parse_3xx()

int ast_sip_redirect_parse_3xx ( pjsip_rx_data *  rdata,
struct ast_sip_redirect_state state 
)

Parse a 3xx redirect response and extract contacts.

This function parses all Contact headers from a 3xx response, extracts q-values, sorts contacts by priority (highest q-value first), and filters out URIs that would create loops.

Parameters
rdataThe redirect response data
stateThe redirect state
Return values
-1on failure (hop limit reached, no valid contacts, etc.)
0on success (at least one valid contact available)
Note
After calling this, use ast_sip_redirect_get_next_uri() to retrieve URIs

Definition at line 338 of file redirect.c.

339{
340 struct redirect_contact_list redirect_contacts;
341 struct redirect_contact *contact;
342 int contact_count;
343 int status_code = rdata->msg_info.msg->line.status.code;
344
345 ast_debug(1, "Received %d redirect response on endpoint '%s'.\n", status_code, ast_sorcery_object_get_id(state->endpoint));
346
347 /* Check if redirect should be followed based on endpoint configuration */
348 if (!ast_sip_should_redirect(state->endpoint, rdata)) {
349 return -1;
350 }
351
352 /* Check hop limit */
353 if (state->hop_count >= AST_SIP_MAX_REDIRECT_HOPS) {
354 ast_log(LOG_WARNING, "Redirect hop limit (%d) reached for endpoint '%s'. Not following redirect.\n",
356 return -1;
357 }
358
359 /* Parse all Contact headers and sort by q-value */
360 AST_LIST_HEAD_INIT_NOLOCK(&redirect_contacts);
361 contact_count = parse_redirect_contacts(rdata, &redirect_contacts, state);
362
363 if (contact_count == 0) {
364 ast_log(LOG_WARNING, "Received %d redirect without valid Contact headers for endpoint '%s'. Cannot follow redirect.\n",
365 status_code, ast_sorcery_object_get_id(state->endpoint));
366 return -1;
367 }
368
369 /* Filter out contacts that would create loops */
370 AST_LIST_TRAVERSE_SAFE_BEGIN(&redirect_contacts, contact, list) {
371 if (is_uri_visited(state, contact->uri)) {
372 ast_log(LOG_WARNING, "Redirect: skipping Contact '%s' for endpoint '%s' (would create loop)\n", contact->uri,
375 ast_free(contact);
376 contact_count--;
377 }
378 }
380
381 if (contact_count == 0) {
382 ast_log(LOG_WARNING, "Redirect: all Contact URIs would create loops for endpoint '%s'. Not following redirect.\n",
384 return -1;
385 }
386
387 /* Move all contacts to pending_contacts list */
388 while ((contact = AST_LIST_REMOVE_HEAD(&redirect_contacts, list))) {
389 AST_LIST_INSERT_TAIL(&state->pending_contacts, contact, list);
390 }
391
392 /* Increment hop count */
393 state->hop_count++;
394
395 return 0;
396}
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
int ast_sip_should_redirect(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Check if redirect should be followed based on endpoint configuration.
Definition redirect.c:140
static int parse_redirect_contacts(pjsip_rx_data *rdata, struct redirect_contact_list *contacts, const struct ast_sip_redirect_state *state)
Definition redirect.c:274
#define AST_SIP_MAX_REDIRECT_HOPS
Maximum number of redirect hops allowed.
List of redirect contacts.
Definition redirect.c:47

References ast_debug, ast_free, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log, AST_SIP_MAX_REDIRECT_HOPS, ast_sip_should_redirect(), ast_sorcery_object_get_id(), is_uri_visited(), redirect_contact::list, LOG_WARNING, parse_redirect_contacts(), and redirect_contact::uri.

Referenced by handle_message_redirect().

◆ ast_sip_redirect_state_create()

struct ast_sip_redirect_state * ast_sip_redirect_state_create ( struct ast_sip_endpoint endpoint,
const char *  initial_uri 
)

Create a new redirect state.

Parameters
endpointThe SIP endpoint
initial_uriThe initial URI being contacted (for loop detection)
Return values
NULLon failure
Anew redirect state on success
Note
The caller must call ast_sip_redirect_state_destroy() when done

Definition at line 59 of file redirect.c.

62{
64 struct visited_uri *visited;
65
66 state = ast_calloc(1, sizeof(*state));
67 if (!state) {
68 return NULL;
69 }
70
71 state->endpoint = ao2_bump(endpoint);
72 state->hop_count = 0;
73 AST_LIST_HEAD_INIT_NOLOCK(&state->visited_uris);
74 AST_LIST_HEAD_INIT_NOLOCK(&state->pending_contacts);
75
76 /* Add the initial URI to visited list */
77 if (initial_uri) {
78 visited = ast_calloc(1, sizeof(*visited));
79 if (visited) {
80 ast_copy_string(visited->uri, initial_uri, sizeof(visited->uri));
81 AST_LIST_INSERT_HEAD(&state->visited_uris, visited, list);
82 } else {
83 ast_log(LOG_WARNING, "Redirect: Memory allocation failed for endpoint '%s'. "
84 "Redirect loop detection may be impaired.\n", ast_sorcery_object_get_id(state->endpoint));
85 }
86 }
87
88 return state;
89}
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define NULL
Definition resample.c:96
Redirect state structure.
Definition redirect.c:52

References ao2_bump, ast_calloc, ast_copy_string(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, ast_log, ast_sorcery_object_get_id(), visited_uri::list, LOG_WARNING, NULL, and visited_uri::uri.

Referenced by message_response_data_create().

◆ ast_sip_redirect_state_destroy()

void ast_sip_redirect_state_destroy ( struct ast_sip_redirect_state state)

Destroy a redirect state and free all resources.

Parameters
stateThe redirect state to destroy

Definition at line 444 of file redirect.c.

445{
446 struct visited_uri *visited;
447 struct redirect_contact *contact;
448
449 if (!state) {
450 return;
451 }
452
453 ao2_cleanup(state->endpoint);
454
455 while ((visited = AST_LIST_REMOVE_HEAD(&state->visited_uris, list))) {
456 ast_free(visited);
457 }
458
459 while ((contact = AST_LIST_REMOVE_HEAD(&state->pending_contacts, list))) {
460 ast_free(contact);
461 }
462
464}
#define ao2_cleanup(obj)
Definition astobj2.h:1934

References ao2_cleanup, ast_free, AST_LIST_REMOVE_HEAD, and redirect_contact::list.

Referenced by message_response_data_destroy().

◆ ast_sip_should_redirect()

int ast_sip_should_redirect ( struct ast_sip_endpoint endpoint,
pjsip_rx_data *  rdata 
)

Check if redirect should be followed based on endpoint configuration.

Parameters
endpointThe SIP endpoint
rdataThe redirect response data containing the 3xx response
Return values
0if redirect should not be followed
1if redirect should be followed
Note
This checks if the status code is 3xx and if the SIP method (extracted from the CSeq header) is allowed to follow redirects based on the endpoint's follow_redirect_methods configuration

Definition at line 140 of file redirect.c.

141{
142 pjsip_msg *msg;
143 pjsip_cseq_hdr *cseq;
144 int status_code;
145
146 if (!rdata || !rdata->msg_info.msg || rdata->msg_info.msg->type != PJSIP_RESPONSE_MSG) {
147 return 0;
148 }
149
150 msg = rdata->msg_info.msg;
151 status_code = msg->line.status.code;
152
153 /* Check if it's a 3xx response */
154 if (!PJSIP_IS_STATUS_IN_CLASS(status_code, 300)) {
155 return 0;
156 }
157
158 /* Extract the method from the CSeq header */
159 cseq = rdata->msg_info.cseq;
160 if (!cseq) {
161 ast_log(LOG_WARNING, "Received %d redirect for endpoint '%s', but no CSeq header found\n",
162 status_code, ast_sorcery_object_get_id(endpoint));
163 return 0;
164 }
165
166 /* Check if this method is allowed to follow redirects */
167 return method_allowed_for_redirect(endpoint, &cseq->method.name);
168}
static int method_allowed_for_redirect(struct ast_sip_endpoint *endpoint, const pj_str_t *method_name)
Definition redirect.c:113

References ast_log, ast_sorcery_object_get_id(), LOG_WARNING, and method_allowed_for_redirect().

Referenced by ast_sip_redirect_parse_3xx().

◆ extract_q_value()

static float extract_q_value ( const pjsip_contact_hdr *  contact)
static

Definition at line 212 of file redirect.c.

213{
214 pjsip_param *param;
215 static const pj_str_t Q_STR = { "q", 1 };
216
217 /* Search for q parameter in the contact header */
218 param = pjsip_param_find(&contact->other_param, &Q_STR);
219 if (!param) {
220 /* No q parameter, use default */
221 return 1.0f;
222 }
223
224 /* Parse the q value */
225 if (param->value.slen > 0) {
226 char q_buf[16];
227 float q_val;
228 int len = param->value.slen < sizeof(q_buf) - 1 ? param->value.slen : sizeof(q_buf) - 1;
229 memcpy(q_buf, param->value.ptr, len);
230 q_buf[len] = '\0';
231
232 q_val = ast_sip_parse_qvalue(q_buf);
233
234 return q_val < 0.0f ? 1.0f : q_val;
235 }
236
237 /* Invalid q value, use default */
238 return 1.0f;
239}
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
float ast_sip_parse_qvalue(const char *q_value)
Parses a string representing a q_value to a float.
Definition res_pjsip.c:3501

References ast_sip_parse_qvalue(), and len().

Referenced by parse_redirect_contacts().

◆ insert_contact_sorted()

static void insert_contact_sorted ( struct redirect_contact_list list,
struct redirect_contact new_contact 
)
static

Definition at line 248 of file redirect.c.

249{
250 struct redirect_contact *contact;
251
252 /* Find the insertion point - contacts with higher q values come first */
254 if (new_contact->q_value > contact->q_value) {
255 /* Insert before this contact */
257 return;
258 }
259 }
261
262 /* If we get here, insert at the end */
263 AST_LIST_INSERT_TAIL(list, new_contact, list);
264}
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.

References AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, redirect_contact::list, and redirect_contact::q_value.

Referenced by parse_redirect_contacts().

◆ is_uri_visited()

static int is_uri_visited ( const struct ast_sip_redirect_state state,
const char *  uri 
)
static

Definition at line 174 of file redirect.c.

175{
176 struct visited_uri *visited;
177
178 AST_LIST_TRAVERSE(&state->visited_uris, visited, list) {
179 if (!strcmp(visited->uri, uri)) {
180 return 1;
181 }
182 }
183 return 0;
184}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.

References AST_LIST_TRAVERSE, visited_uri::list, and visited_uri::uri.

Referenced by ast_sip_redirect_check_loop(), and ast_sip_redirect_parse_3xx().

◆ method_allowed_for_redirect()

static int method_allowed_for_redirect ( struct ast_sip_endpoint endpoint,
const pj_str_t *  method_name 
)
static

Definition at line 113 of file redirect.c.

114{
115 int i;
116
117 /* Look up the method in our mapping table */
118 for (i = 0; i < ARRAY_LEN(redirect_methods); i++) {
119 if (pj_stricmp2(method_name, redirect_methods[i].method_name) == 0) {
120 /* Method is recognized, check if it's allowed */
122 return 1;
123 } else {
124 ast_log(LOG_NOTICE, "Received redirect for %s to endpoint '%s', "
125 "but %s is not in follow_redirect_methods. Not following redirect.\n",
126 redirect_methods[i].method_name,
127 ast_sorcery_object_get_id(endpoint), redirect_methods[i].method_name);
128 return 0;
129 }
130 }
131 }
132
133 /* Method not recognized/supported for redirects */
134 ast_log(LOG_NOTICE, "Received redirect for method %.*s to endpoint '%s', "
135 "but this method is not supported in follow_redirect_methods. Not following redirect.\n",
136 (int)method_name->slen, method_name->ptr, ast_sorcery_object_get_id(endpoint));
137 return 0;
138}
#define LOG_NOTICE
static const struct redirect_method_map redirect_methods[]
Definition redirect.c:99
struct ast_flags follow_redirect_methods
Definition res_pjsip.h:1128
enum ast_sip_redirect_method flag
#define ast_test_flag(p, flag)
Definition utils.h:64
#define ARRAY_LEN(a)
Definition utils.h:706

References ARRAY_LEN, ast_log, ast_sorcery_object_get_id(), ast_test_flag, redirect_method_map::flag, ast_sip_endpoint::follow_redirect_methods, LOG_NOTICE, redirect_method_map::method_name, and redirect_methods.

Referenced by ast_sip_should_redirect().

◆ parse_redirect_contacts()

static int parse_redirect_contacts ( pjsip_rx_data *  rdata,
struct redirect_contact_list contacts,
const struct ast_sip_redirect_state state 
)
static

Definition at line 274 of file redirect.c.

275{
276 pjsip_contact_hdr *contact_hdr;
277 pjsip_uri *contact_uri;
278 int count = 0;
279 void *start = NULL;
280
281 /* Iterate through all Contact headers */
282 while ((contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, start))) {
284 int len;
285
286 start = contact_hdr->next;
287
288 /* Enforce maximum contact limit to prevent resource exhaustion */
289 if (count >= AST_SIP_MAX_REDIRECT_CONTACTS) {
290 ast_log(LOG_WARNING, "Redirect: maximum Contact header limit (%d) reached for endpoint '%s'. Ignoring additional contacts\n",
292 break;
293 }
294
295 if (!contact_hdr->uri) {
296 continue;
297 }
298
299 contact_uri = (pjsip_uri *)pjsip_uri_get_uri(contact_hdr->uri);
300
301 /* Verify it's a SIP URI */
302 if (!PJSIP_URI_SCHEME_IS_SIP(contact_uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_uri)) {
303 ast_debug(1, "Skipping non-SIP/SIPS Contact URI in redirect for endpoint '%s'\n", ast_sorcery_object_get_id(state->endpoint));
304 continue;
305 }
306
307 /* Allocate a new redirect_contact structure */
309 if (!redirect_contact) {
310 ast_log(LOG_ERROR, "Failed to allocate memory for redirect contact for endpoint '%s'.\n", ast_sorcery_object_get_id(state->endpoint));
311 continue;
312 }
313
314 /* Print the URI */
315 len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, contact_uri,
317 if (len < 1) {
318 ast_debug(1, "Contact URI too long for redirect on endpoint '%s'. Skipping.\n", ast_sorcery_object_get_id(state->endpoint));
320 continue;
321 }
322 redirect_contact->uri[len] = '\0';
323
324 /* Extract q-value */
326
327 ast_debug(1, "Found redirect Contact: %s (q=%f) for endpoint '%s'.\n", redirect_contact->uri, redirect_contact->q_value,
329
330 /* Insert into sorted list */
332 count++;
333 }
334
335 return count;
336}
#define LOG_ERROR
static void insert_contact_sorted(struct redirect_contact_list *list, struct redirect_contact *new_contact)
Definition redirect.c:248
static float extract_q_value(const pjsip_contact_hdr *contact)
Definition redirect.c:212
#define AST_SIP_MAX_REDIRECT_CONTACTS
Maximum number of redirect contacts to process.
struct redirect_contact * next
Definition redirect.c:43

References ast_calloc, ast_debug, ast_free, ast_log, AST_SIP_MAX_REDIRECT_CONTACTS, ast_sorcery_object_get_id(), extract_q_value(), insert_contact_sorted(), len(), LOG_ERROR, LOG_WARNING, redirect_contact::next, NULL, redirect_contact::q_value, and redirect_contact::uri.

Referenced by ast_sip_redirect_parse_3xx().

Variable Documentation

◆ redirect_methods

const struct redirect_method_map redirect_methods[]
static
Initial value:
= {
}
@ AST_SIP_REDIRECT_METHOD_MESSAGE
Definition res_pjsip.h:760

Definition at line 99 of file redirect.c.

99 {
100 { "MESSAGE", AST_SIP_REDIRECT_METHOD_MESSAGE },
101};

Referenced by method_allowed_for_redirect().