Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
Macros | Functions
res_pjsip_redirect.h File Reference
#include <pjsip.h>
Include dependency graph for res_pjsip_redirect.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define AST_SIP_MAX_REDIRECT_CONTACTS   20
 Maximum number of redirect contacts to process.
 
#define AST_SIP_MAX_REDIRECT_HOPS   5
 Maximum number of redirect hops allowed.
 

Functions

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.
 

Macro Definition Documentation

◆ AST_SIP_MAX_REDIRECT_CONTACTS

#define AST_SIP_MAX_REDIRECT_CONTACTS   20

Maximum number of redirect contacts to process.

Definition at line 32 of file res_pjsip_redirect.h.

◆ AST_SIP_MAX_REDIRECT_HOPS

#define AST_SIP_MAX_REDIRECT_HOPS   5

Maximum number of redirect hops allowed.

Definition at line 27 of file res_pjsip_redirect.h.

Function Documentation

◆ 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_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#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 ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
Redirect state structure.
Definition redirect.c:52
struct visited_uri::@495 list
char uri[PJSIP_MAX_URL_SIZE]
Definition redirect.c:32

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().