- Timestamp:
- Nov 27, 2008 12:06:46 AM (16 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 3 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
r2316 r2370 63 63 pjsua_transport_config udp_cfg; 64 64 pjsua_transport_config rtp_cfg; 65 pjsip_redirect_op redir_op; 65 66 66 67 unsigned acc_cnt; … … 279 280 puts (" --use-compact-form Minimize SIP message size"); 280 281 puts (" --no-force-lr Allow strict-route to be used (i.e. do not force lr)"); 282 puts (" --accept-redirect=N Specify how to handle call redirect (3xx) response."); 283 puts (" 0: reject, 1: follow automatically (default), 2: ask"); 281 284 282 285 puts (""); … … 304 307 pjsua_transport_config_default(&cfg->rtp_cfg); 305 308 cfg->rtp_cfg.port = 4000; 309 cfg->redir_op = PJSIP_REDIRECT_ACCEPT; 306 310 cfg->duration = NO_LIMIT; 307 311 cfg->wav_id = PJSUA_INVALID_ID; … … 473 477 OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, 474 478 OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP, OPT_THREAD_CNT, 475 OPT_NOREFERSUB, 479 OPT_NOREFERSUB, OPT_ACCEPT_REDIRECT, 476 480 OPT_USE_TLS, OPT_TLS_CA_FILE, OPT_TLS_CERT_FILE, OPT_TLS_PRIV_FILE, 477 481 OPT_TLS_PASSWORD, OPT_TLS_VERIFY_SERVER, OPT_TLS_VERIFY_CLIENT, … … 516 520 { "auto-update-nat", 1, 0, OPT_AUTO_UPDATE_NAT}, 517 521 { "use-compact-form", 0, 0, OPT_USE_COMPACT_FORM}, 522 { "accept-redirect", 1, 0, OPT_ACCEPT_REDIRECT}, 518 523 { "no-force-lr",0, 0, OPT_NO_FORCE_LR}, 519 524 { "realm", 1, 0, OPT_REALM}, … … 841 846 break; 842 847 848 case OPT_ACCEPT_REDIRECT: 849 cfg->redir_op = my_atoi(pj_optarg); 850 if (cfg->redir_op<0 || cfg->redir_op>PJSIP_REDIRECT_STOP) { 851 PJ_LOG(1,(THIS_FILE, 852 "Error: accept-redirect value '%s' ", pj_optarg)); 853 return PJ_EINVAL; 854 } 855 break; 856 843 857 case OPT_NO_FORCE_LR: 844 858 cfg->cfg.force_lr = PJ_FALSE; … … 1786 1800 } 1787 1801 1802 /* accept-redirect */ 1803 if (config->redir_op != PJSIP_REDIRECT_ACCEPT) { 1804 pj_ansi_sprintf(line, "--accept-redirect %d\n", 1805 config->redir_op); 1806 pj_strcat2(&cfg, line); 1807 } 1808 1788 1809 /* Max calls. */ 1789 1810 pj_ansi_sprintf(line, "--max-calls %d\n", … … 1841 1862 * as the logger can accept. 1842 1863 */ 1843 static void log_call_dump(int call_id) { 1864 static void log_call_dump(int call_id) 1865 { 1844 1866 unsigned call_dump_len; 1845 1867 unsigned part_len; … … 2367 2389 { 2368 2390 PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c", call_id, dtmf)); 2391 } 2392 2393 /* 2394 * Redirection handler. 2395 */ 2396 static void call_on_redirected(pjsua_call_id call_id, const pjsip_uri *target, 2397 pjsip_redirect_op *cmd, const pjsip_event *e) 2398 { 2399 *cmd = app_config.redir_op; 2400 2401 PJ_UNUSED_ARG(e); 2402 2403 if (*cmd == PJSIP_REDIRECT_PENDING) { 2404 char uristr[PJSIP_MAX_URL_SIZE]; 2405 int len; 2406 2407 len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, target, uristr, 2408 sizeof(uristr)); 2409 if (len < 1) { 2410 pj_ansi_strcpy(uristr, "--URI too long--"); 2411 } 2412 2413 PJ_LOG(3,(THIS_FILE, "Call %d is being redirected to %.*s. " 2414 "Press 'Ra' to accept, 'Rr' to reject, or 'Rd' to " 2415 "disconnect.", 2416 call_id, len, uristr)); 2417 } 2369 2418 } 2370 2419 … … 3916 3965 3917 3966 3967 case 'R': 3968 if (!pjsua_call_is_active(current_call)) { 3969 PJ_LOG(1,(THIS_FILE, "Call %d has gone", current_call)); 3970 } else if (menuin[1] == 'a') { 3971 pjsua_call_process_redirect(current_call, 3972 PJSIP_REDIRECT_ACCEPT); 3973 } else if (menuin[1] == 'r') { 3974 pjsua_call_process_redirect(current_call, 3975 PJSIP_REDIRECT_REJECT); 3976 } else { 3977 pjsua_call_process_redirect(current_call, 3978 PJSIP_REDIRECT_STOP); 3979 } 3980 break; 3981 3918 3982 default: 3919 3983 if (menuin[0] != '\n' && menuin[0] != '\r') { … … 3963 4027 app_config.cfg.cb.on_call_tsx_state = &on_call_tsx_state; 3964 4028 app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback; 4029 app_config.cfg.cb.on_call_redirected = &call_on_redirected; 3965 4030 app_config.cfg.cb.on_reg_state = &on_reg_state; 3966 4031 app_config.cfg.cb.on_incoming_subscribe = &on_incoming_subscribe; -
pjproject/trunk/pjsip-apps/src/test-pjsua/mod_recvfrom.py
r2110 r2370 1 # $Id :$1 # $Id$ 2 2 import imp 3 3 import sys … … 68 68 raise TestError("Excluded pattern " + pat + " found" + tname) 69 69 # Create response 70 response = dlg.create_response(request, t.resp_code, "Status reason") 71 # Add headers to response 72 for h in t.resp_hdr: 73 response = response + h + "\r\n" 74 # Add message body if required 75 if t.body: 76 response = response + t.body 77 # Send response 78 dlg.send_msg(response, src_addr) 70 if t.resp_code!=0: 71 response = dlg.create_response(request, t.resp_code, "Status reason") 72 # Add headers to response 73 for h in t.resp_hdr: 74 response = response + h + "\r\n" 75 # Add message body if required 76 if t.body: 77 response = response + t.body 78 # Send response 79 dlg.send_msg(response, src_addr) 80 79 81 # Expect something to happen in pjsua 80 82 if t.expect != "": -
pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h
r2039 r2370 116 116 void (*on_state_changed)(pjsip_inv_session *inv, pjsip_event *e); 117 117 118 119 118 /** 120 119 * This callback is called when the invite usage module has created … … 214 213 */ 215 214 void (*on_send_ack)(pjsip_inv_session *inv, pjsip_rx_data *rdata); 215 216 /** 217 * This callback is called when the session is about to resend the 218 * INVITE request to the specified target, following the previously 219 * received redirection response. 220 * 221 * Application may accept the redirection to the specified target 222 * (the default behavior if this callback is implemented), reject 223 * this target only and make the session continue to try the next 224 * target in the list if such target exists, stop the whole 225 * redirection process altogether and cause the session to be 226 * disconnected, or defer the decision to ask for user confirmation. 227 * 228 * This callback is optional. If this callback is not implemented, 229 * the default behavior is to NOT follow the redirection response. 230 * 231 * @param inv The invite session. 232 * @param target The current target to be tried. 233 * @param cmd Action to be performed for the target. Set this 234 * parameter to one of the value below: 235 * - PJSIP_REDIRECT_ACCEPT: immediately accept the 236 * redirection (default value). When set, the 237 * session will immediately resend INVITE request 238 * to the target. 239 * - PJSIP_REDIRECT_REJECT: immediately reject this 240 * target. The session will continue retrying with 241 * next target if present, or disconnect the call 242 * if there is no more target to try. 243 * - PJSIP_REDIRECT_STOP: stop the whole redirection 244 * process and immediately disconnect the call. The 245 * on_state_changed() callback will be called with 246 * PJSIP_INV_STATE_DISCONNECTED state immediately 247 * after this callback returns. 248 * - PJSIP_REDIRECT_PENDING: set to this value if 249 * no decision can be made immediately (for example 250 * to request confirmation from user). Application 251 * then MUST call #pjsip_inv_process_redirect() 252 * to either accept or reject the redirection upon 253 * getting user decision. 254 * @param e The event that caused this callback to be called. 255 * This could be the receipt of 3xx response, or 256 * 4xx/5xx response received for the INVITE sent to 257 * subsequent targets, or NULL if this callback is 258 * called from within #pjsip_inv_process_redirect() 259 * context. 260 */ 261 void (*on_redirected)(pjsip_inv_session *inv, const pjsip_uri *target, 262 pjsip_redirect_op *cmd, const pjsip_event *e); 216 263 217 264 } pjsip_inv_callback; … … 277 324 pjmedia_sdp_neg *neg; /**< Negotiator. */ 278 325 pjsip_transaction *invite_tsx; /**< 1st invite tsx. */ 326 pjsip_tx_data *invite_req; /**< Saved invite req */ 279 327 pjsip_tx_data *last_answer; /**< Last INVITE resp. */ 280 328 pjsip_tx_data *last_ack; /**< Last ACK request */ … … 473 521 int st_code, 474 522 pj_bool_t notify ); 523 524 525 /** 526 * Restart UAC session and prepare the session for a new initial INVITE. 527 * This function can be called for example when the application wants to 528 * follow redirection response with a new call reusing this session so 529 * that the new call will have the same Call-ID and From headers. After 530 * the session is restarted, application may create and send a new INVITE 531 * request. 532 * 533 * @param inv The invite session. 534 * @param new_offer Should be set to PJ_TRUE since the application will 535 * restart the session. 536 * 537 * @return PJ_SUCCESS on successful operation. 538 */ 539 PJ_DECL(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv, 540 pj_bool_t new_offer); 541 542 543 /** 544 * Accept or reject redirection response. Application MUST call this function 545 * after it signaled PJSIP_REDIRECT_PENDING in the \a on_redirected() 546 * callback, to notify the invite session whether to accept or reject the 547 * redirection to the current target. Application can use the combination of 548 * PJSIP_REDIRECT_PENDING command in \a on_redirected() callback and this 549 * function to ask for user permission before redirecting the call. 550 * 551 * Note that if the application chooses to reject or stop redirection (by 552 * using PJSIP_REDIRECT_REJECT or PJSIP_REDIRECT_STOP respectively), the 553 * session disconnection callback will be called before this function returns. 554 * And if the application rejects the target, the \a on_redirected() callback 555 * may also be called before this function returns if there is another target 556 * to try. 557 * 558 * @param inv The invite session. 559 * @param cmd Redirection operation. The semantic of this argument 560 * is similar to the description in the \a on_redirected() 561 * callback, except that the PJSIP_REDIRECT_PENDING is 562 * not accepted here. 563 * @param e Should be set to NULL. 564 * 565 * @return PJ_SUCCESS on successful operation. 566 */ 567 PJ_DECL(pj_status_t) pjsip_inv_process_redirect(pjsip_inv_session *inv, 568 pjsip_redirect_op cmd, 569 pjsip_event *e); 475 570 476 571 -
pjproject/trunk/pjsip/include/pjsip/sip_dialog.h
r2039 r2370 30 30 #include <pjsip/sip_errno.h> 31 31 #include <pjsip/sip_transport.h> 32 #include <pjsip/sip_util.h> 32 33 #include <pj/sock.h> 33 34 #include <pj/assert.h> … … 122 123 pjsip_dialog_state state; /**< Dialog state. */ 123 124 pjsip_uri *target; /**< Current target. */ 125 pjsip_target_set target_set; /**< Target set, for UAC only. */ 124 126 pjsip_hdr inv_hdr; /**< Headers from hparam in dest URL */ 125 127 pjsip_dlg_party local; /**< Local party info. */ -
pjproject/trunk/pjsip/include/pjsip/sip_util.h
r2039 r2370 25 25 26 26 PJ_BEGIN_DECL 27 28 /** 29 * @defgroup PJSIP_ENDPT_TARGET_URI Target URI Management 30 * @ingroup PJSIP_CORE_CORE 31 * @brief Management of target URI's in case of redirection 32 * @{ 33 * This module provides utility functions to manage target set for UAC. 34 * The target set is provided as pjsip_target_set structure. Initially, 35 * the target set for UAC contains only one target, that is the target of 36 * the initial request. When 3xx/redirection class response is received, 37 * the UAC can use the functionality of this module to add the URI's listed 38 * in the Contact header(s) in the response to the target set, and retry 39 * sending the request to the next destination/target. The UAC may retry 40 * this sequentially until one of the target answers with succesful/2xx 41 * response, or one target returns global error/6xx response, or all targets 42 * are exhausted. 43 * 44 * This module is currently used by the \ref PJSIP_INV. 45 */ 46 47 /** 48 * This structure describes a target, which can be chained together to form 49 * a target set. Each target contains an URI, priority (as q-value), and 50 * the last status code and reason phrase received from the target, if the 51 * target has been contacted. If the target has not been contacted, the 52 * status code field will be zero. 53 */ 54 typedef struct pjsip_target 55 { 56 PJ_DECL_LIST_MEMBER(struct pjsip_target);/**< Standard list element */ 57 pjsip_uri *uri; /**< The target URI */ 58 int q1000; /**< q-value multiplied by 1000 */ 59 pjsip_status_code code; /**< Last status code received */ 60 pj_str_t reason; /**< Last reason phrase received */ 61 } pjsip_target; 62 63 64 /** 65 * This describes a target set. A target set contains a linked-list of 66 * pjsip_target. 67 */ 68 typedef struct pjsip_target_set 69 { 70 pjsip_target head; /**< Target linked-list head */ 71 pjsip_target *current; /**< Current target. */ 72 } pjsip_target_set; 73 74 75 /** 76 * These enumerations specify the action to be performed to a redirect 77 * response. 78 */ 79 typedef enum pjsip_redirect_op 80 { 81 /** 82 * Reject the redirection to the current target. The UAC will 83 * select the next target from the target set if exists. 84 */ 85 PJSIP_REDIRECT_REJECT, 86 87 /** 88 * Accept the redirection to the current target. The INVITE request 89 * will be resent to the current target. 90 */ 91 PJSIP_REDIRECT_ACCEPT, 92 93 /** 94 * Defer the redirection decision, for example to request permission 95 * from the end user. 96 */ 97 PJSIP_REDIRECT_PENDING, 98 99 /** 100 * Stop the whole redirection process altogether. This will cause 101 * the invite session to be disconnected. 102 */ 103 PJSIP_REDIRECT_STOP 104 105 } pjsip_redirect_op; 106 107 108 /** 109 * Initialize target set. This will empty the list of targets in the 110 * target set. 111 * 112 * @param tset The target set. 113 */ 114 PJ_INLINE(void) pjsip_target_set_init(pjsip_target_set *tset) 115 { 116 pj_list_init(&tset->head); 117 tset->current = NULL; 118 } 119 120 121 /** 122 * Add an URI to the target set, if the URI is not already in the target set. 123 * The URI comparison rule of pjsip_uri_cmp() will be used to determine the 124 * equality of this URI compared to existing URI's in the target set. The 125 * URI will be cloned using the specified memory pool before it is added to 126 * the list. 127 * 128 * The first URI added to the target set will also be made current target 129 * by this function. 130 * 131 * @param tset The target set. 132 * @param pool The memory pool to be used to duplicate the URI. 133 * @param uri The URI to be checked and added. 134 * @param q1000 The q-value multiplied by 1000. 135 * 136 * @return PJ_SUCCESS if the URI was added to the target set, 137 * or PJ_EEXISTS if the URI already exists in the target 138 * set, or other error codes. 139 */ 140 PJ_DECL(pj_status_t) pjsip_target_set_add_uri(pjsip_target_set *tset, 141 pj_pool_t *pool, 142 const pjsip_uri *uri, 143 int q1000); 144 145 /** 146 * Extract URI's in the Contact headers of the specified (response) message 147 * and add them to the target set. This function will also check if the 148 * URI's already exist in the target set before adding them to the list. 149 * 150 * @param tset The target set. 151 * @param pool The memory pool to be used to duplicate the URI's. 152 * @param msg SIP message from which the Contact headers will be 153 * scanned and the URI's to be extracted, checked, and 154 * added to the target set. 155 * 156 * @return PJ_SUCCESS if at least one URI was added to the 157 * target set, or PJ_EEXISTS if all URI's in the message 158 * already exists in the target set or if the message 159 * doesn't contain usable Contact headers, or other error 160 * codes. 161 */ 162 PJ_DECL(pj_status_t) pjsip_target_set_add_from_msg(pjsip_target_set *tset, 163 pj_pool_t *pool, 164 const pjsip_msg *msg); 165 166 /** 167 * Get the next target to be retried. This function will scan the target set 168 * for target which hasn't been tried, and return one target with the 169 * highest q-value, if such target exists. This function will return NULL 170 * if there is one target with 2xx or 6xx code or if all targets have been 171 * tried. 172 * 173 * @param tset The target set. 174 * 175 * @return The next target to be tried, or NULL if all targets have 176 * been tried or at least one target returns 2xx or 6xx 177 * response. 178 */ 179 PJ_DECL(pjsip_target*) 180 pjsip_target_set_get_next(const pjsip_target_set *tset); 181 182 183 /** 184 * Set the specified target as the current target in the target set. The 185 * current target may be used by application to keep track on which target 186 * is currently being operated on. 187 * 188 * @param tset The target set. 189 * @param target The target to be set as current target. 190 * 191 * @return PJ_SUCCESS or the appropriate error code. 192 */ 193 PJ_DECL(pj_status_t) pjsip_target_set_set_current(pjsip_target_set *tset, 194 pjsip_target *target); 195 196 197 /** 198 * Set the status code and reason phrase of the specified target. 199 * 200 * @param target The target. 201 * @param pool The memory pool to be used to duplicate the reason phrase. 202 * @param code The SIP status code to be set to the target. 203 * @param reason The reason phrase to be set to the target. 204 * 205 * @return PJ_SUCCESS on successful operation or the appropriate 206 * error code. 207 */ 208 PJ_DECL(pj_status_t) pjsip_target_assign_status(pjsip_target *target, 209 pj_pool_t *pool, 210 int status_code, 211 const pj_str_t *reason); 212 213 /** 214 * @} 215 */ 27 216 28 217 /** -
pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
r2351 r2370 1063 1063 void (*on_nat_detect)(const pj_stun_nat_detect_result *res); 1064 1064 1065 /** 1066 * This callback is called when the call is about to resend the 1067 * INVITE request to the specified target, following the previously 1068 * received redirection response. 1069 * 1070 * Application may accept the redirection to the specified target 1071 * (the default behavior if this callback is implemented), reject 1072 * this target only and make the session continue to try the next 1073 * target in the list if such target exists, stop the whole 1074 * redirection process altogether and cause the session to be 1075 * disconnected, or defer the decision to ask for user confirmation. 1076 * 1077 * This callback is optional. If this callback is not implemented, 1078 * the default behavior is to NOT follow the redirection response. 1079 * 1080 * @param call_id The call ID. 1081 * @param target The current target to be tried. 1082 * @param cmd Action to be performed for the target. Set this 1083 * parameter to one of the value below: 1084 * - PJSIP_REDIRECT_ACCEPT: immediately accept the 1085 * redirection (default value). When set, the 1086 * call will immediately resend INVITE request 1087 * to the target. 1088 * - PJSIP_REDIRECT_REJECT: immediately reject this 1089 * target. The call will continue retrying with 1090 * next target if present, or disconnect the call 1091 * if there is no more target to try. 1092 * - PJSIP_REDIRECT_STOP: stop the whole redirection 1093 * process and immediately disconnect the call. The 1094 * on_call_state() callback will be called with 1095 * PJSIP_INV_STATE_DISCONNECTED state immediately 1096 * after this callback returns. 1097 * - PJSIP_REDIRECT_PENDING: set to this value if 1098 * no decision can be made immediately (for example 1099 * to request confirmation from user). Application 1100 * then MUST call #pjsua_call_process_redirect() 1101 * to either accept or reject the redirection upon 1102 * getting user decision. 1103 * @param e The event that caused this callback to be called. 1104 * This could be the receipt of 3xx response, or 1105 * 4xx/5xx response received for the INVITE sent to 1106 * subsequent targets, or NULL if this callback is 1107 * called from within #pjsua_call_process_redirect() 1108 * context. 1109 */ 1110 void (*on_call_redirected)(pjsua_call_id call_id, const pjsip_uri *target, 1111 pjsip_redirect_op *cmd, const pjsip_event *e); 1112 1065 1113 } pjsua_callback; 1066 1114 … … 3133 3181 const pjsua_msg_data *msg_data); 3134 3182 3183 /** 3184 * Accept or reject redirection response. Application MUST call this function 3185 * after it signaled PJSIP_REDIRECT_PENDING in the \a on_call_redirected() 3186 * callback, to notify the call whether to accept or reject the redirection 3187 * to the current target. Application can use the combination of 3188 * PJSIP_REDIRECT_PENDING command in \a on_call_redirected() callback and 3189 * this function to ask for user permission before redirecting the call. 3190 * 3191 * Note that if the application chooses to reject or stop redirection (by 3192 * using PJSIP_REDIRECT_REJECT or PJSIP_REDIRECT_STOP respectively), the 3193 * call disconnection callback will be called before this function returns. 3194 * And if the application rejects the target, the \a on_call_redirected() 3195 * callback may also be called before this function returns if there is 3196 * another target to try. 3197 * 3198 * @param call_id The call ID. 3199 * @param cmd Redirection operation to be applied to the current 3200 * target. The semantic of this argument is similar 3201 * to the description in the \a on_call_redirected() 3202 * callback, except that the PJSIP_REDIRECT_PENDING is 3203 * not accepted here. 3204 * 3205 * @return PJ_SUCCESS on successful operation. 3206 */ 3207 PJ_DECL(pj_status_t) pjsua_call_process_redirect(pjsua_call_id call_id, 3208 pjsip_redirect_op cmd); 3135 3209 3136 3210 /** -
pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
r2362 r2370 226 226 inv->last_ack = NULL; 227 227 } 228 if (inv->invite_req) { 229 pjsip_tx_data_dec_ref(inv->invite_req); 230 inv->invite_req = NULL; 231 } 228 232 pjsip_100rel_end_session(inv); 229 233 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); … … 1220 1224 1221 1225 1226 /* 1227 * Restart UAC session, possibly because app or us wants to re-send the 1228 * INVITE request due to 401/407 challenge or 3xx response. 1229 */ 1230 PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv, 1231 pj_bool_t new_offer) 1232 { 1233 PJ_ASSERT_RETURN(inv, PJ_EINVAL); 1234 1235 inv->state = PJSIP_INV_STATE_NULL; 1236 inv->invite_tsx = NULL; 1237 if (inv->last_answer) { 1238 pjsip_tx_data_dec_ref(inv->last_answer); 1239 inv->last_answer = NULL; 1240 } 1241 1242 if (new_offer && inv->neg) { 1243 pjmedia_sdp_neg_state neg_state; 1244 1245 neg_state = pjmedia_sdp_neg_get_state(inv->neg); 1246 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) { 1247 pjmedia_sdp_neg_cancel_offer(inv->neg); 1248 } 1249 } 1250 1251 return PJ_SUCCESS; 1252 } 1253 1254 1222 1255 static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len) 1223 1256 { … … 1890 1923 1891 1924 return PJ_SUCCESS; 1925 } 1926 1927 /* Following redirection recursion, get next target from the target set and 1928 * notify user. 1929 * 1930 * Returns PJ_FALSE if recursion fails (either because there's no more target 1931 * or user rejects the recursion). If we return PJ_FALSE, caller should 1932 * disconnect the session. 1933 * 1934 * Note: 1935 * the event 'e' argument may be NULL. 1936 */ 1937 static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code, 1938 const pj_str_t *reason, pjsip_event *e) 1939 { 1940 pjsip_redirect_op op = PJSIP_REDIRECT_ACCEPT; 1941 pjsip_target *target; 1942 1943 /* Won't redirect if the callback is not implemented. */ 1944 if (mod_inv.cb.on_redirected == NULL) 1945 return PJ_FALSE; 1946 1947 if (reason == NULL) 1948 reason = pjsip_get_status_text(code); 1949 1950 /* Set status of current target */ 1951 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool, 1952 code, reason); 1953 1954 /* Fetch next target from the target set. We only want to 1955 * process SIP/SIPS URI for now. 1956 */ 1957 for (;;) { 1958 target = pjsip_target_set_get_next(&inv->dlg->target_set); 1959 if (target == NULL) { 1960 /* No more target. */ 1961 return PJ_FALSE; 1962 } 1963 1964 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) && 1965 !PJSIP_URI_SCHEME_IS_SIPS(target->uri)) 1966 { 1967 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME; 1968 reason = pjsip_get_status_text(code); 1969 1970 /* Mark this target as unusable and fetch next target. */ 1971 pjsip_target_assign_status(target, inv->dlg->pool, code, reason); 1972 } else { 1973 /* Found a target */ 1974 break; 1975 } 1976 } 1977 1978 /* We have target in 'target'. Set this target as current target 1979 * and notify callback. 1980 */ 1981 pjsip_target_set_set_current(&inv->dlg->target_set, target); 1982 1983 (*mod_inv.cb.on_redirected)(inv, target->uri, &op, e); 1984 1985 1986 /* Check what the application wants to do now */ 1987 switch (op) { 1988 case PJSIP_REDIRECT_ACCEPT: 1989 case PJSIP_REDIRECT_STOP: 1990 /* Must increment session counter, that's the convention of the 1991 * pjsip_inv_process_redirect(). 1992 */ 1993 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod); 1994 1995 /* Act on the recursion */ 1996 pjsip_inv_process_redirect(inv, op, e); 1997 return PJ_TRUE; 1998 1999 case PJSIP_REDIRECT_PENDING: 2000 /* Increment session so that the dialog/session is not destroyed 2001 * while we're waiting for user confirmation. 2002 */ 2003 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod); 2004 2005 /* Also clear the invite_tsx variable, otherwise when this tsx is 2006 * terminated, it will also terminate the session. 2007 */ 2008 inv->invite_tsx = NULL; 2009 2010 /* Done. The processing will continue once the application calls 2011 * pjsip_inv_process_redirect(). 2012 */ 2013 return PJ_TRUE; 2014 2015 case PJSIP_REDIRECT_REJECT: 2016 /* Recursively call this function again to fetch next target, if any. 2017 */ 2018 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e); 2019 2020 } 2021 2022 pj_assert(!"Should not reach here"); 2023 return PJ_FALSE; 2024 } 2025 2026 2027 /* Process redirection/recursion */ 2028 PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv, 2029 pjsip_redirect_op op, 2030 pjsip_event *e) 2031 { 2032 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED; 2033 pjsip_event usr_event; 2034 pj_status_t status = PJ_SUCCESS; 2035 2036 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL); 2037 2038 if (e == NULL) { 2039 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL); 2040 e = &usr_event; 2041 } 2042 2043 pjsip_dlg_inc_lock(inv->dlg); 2044 2045 /* Decrement session. That's the convention here to prevent the dialog 2046 * or session from being destroyed while we're waiting for user 2047 * confirmation. 2048 */ 2049 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); 2050 2051 /* See what the application wants to do now */ 2052 switch (op) { 2053 case PJSIP_REDIRECT_ACCEPT: 2054 /* User accept the redirection. Reset the session and resend the 2055 * INVITE request. 2056 */ 2057 { 2058 pjsip_tx_data *tdata; 2059 pjsip_via_hdr *via; 2060 2061 /* Get the original INVITE request. */ 2062 tdata = inv->invite_req; 2063 pjsip_tx_data_add_ref(tdata); 2064 2065 /* Restore strict route set. 2066 * See http://trac.pjsip.org/repos/ticket/492 2067 */ 2068 pjsip_restore_strict_route_set(tdata); 2069 2070 /* Set target */ 2071 tdata->msg->line.req.uri = 2072 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri); 2073 2074 /* Remove branch param in Via header. */ 2075 via = (pjsip_via_hdr*) 2076 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); 2077 via->branch_param.slen = 0; 2078 2079 /* Must invalidate the message! */ 2080 pjsip_tx_data_invalidate_msg(tdata); 2081 2082 /* Reset the session */ 2083 pjsip_inv_uac_restart(inv, PJ_FALSE); 2084 2085 /* (re)Send the INVITE request */ 2086 status = pjsip_inv_send_msg(inv, tdata); 2087 } 2088 break; 2089 2090 case PJSIP_REDIRECT_STOP: 2091 /* User doesn't want the redirection. Disconnect the session now. */ 2092 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code)); 2093 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 2094 2095 /* Caller should expect that the invite session is gone now, so 2096 * we don't need to set status to PJSIP_ESESSIONTERMINATED here. 2097 */ 2098 break; 2099 2100 case PJSIP_REDIRECT_REJECT: 2101 /* Current target is rejected. Fetch next target if any. */ 2102 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) { 2103 inv_set_cause(inv, cancel_code, 2104 pjsip_get_status_text(cancel_code)); 2105 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 2106 2107 /* Tell caller that the invite session is gone now */ 2108 status = PJSIP_ESESSIONTERMINATED; 2109 } 2110 break; 2111 2112 2113 case PJSIP_REDIRECT_PENDING: 2114 pj_assert(!"Should not happen"); 2115 break; 2116 } 2117 2118 2119 pjsip_dlg_dec_lock(inv->dlg); 2120 2121 return status; 1892 2122 } 1893 2123 … … 2553 2783 if (dlg->role == PJSIP_ROLE_UAC) { 2554 2784 2785 /* Save the original INVITE request, if on_redirected() callback 2786 * is implemented. We may need to resend the INVITE if we receive 2787 * redirection response. 2788 */ 2789 if (mod_inv.cb.on_redirected) { 2790 if (inv->invite_req) { 2791 pjsip_tx_data_dec_ref(inv->invite_req); 2792 inv->invite_req = NULL; 2793 } 2794 inv->invite_req = tsx->last_tx; 2795 pjsip_tx_data_add_ref(inv->invite_req); 2796 } 2797 2555 2798 switch (tsx->state) { 2556 2799 case PJSIP_TSX_STATE_CALLING: … … 2674 2917 2675 2918 2919 /* Handle call rejection, especially with regard to processing call 2920 * redirection. We need to handle the following scenarios: 2921 * - 3xx response is received -- see if on_redirected() callback is 2922 * implemented. If so, add the Contact URIs in the response to the 2923 * target set and notify user. 2924 * - 4xx - 6xx resposne is received -- see if we're currently recursing, 2925 * if so fetch the next target if any and notify the on_redirected() 2926 * callback. 2927 * - for other cases -- disconnect the session. 2928 */ 2929 static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e) 2930 { 2931 pjsip_transaction *tsx = e->body.tsx_state.tsx; 2932 pj_status_t status; 2933 2934 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) { 2935 2936 if (mod_inv.cb.on_redirected == NULL) { 2937 2938 /* Redirection callback is not implemented, disconnect the 2939 * call. 2940 */ 2941 goto terminate_session; 2942 2943 } else { 2944 const pjsip_msg *res_msg; 2945 2946 res_msg = e->body.tsx_state.src.rdata->msg_info.msg; 2947 2948 /* Gather all Contact URI's in the response and add them 2949 * to target set. The function will take care of removing 2950 * duplicate URI's. 2951 */ 2952 pjsip_target_set_add_from_msg(&inv->dlg->target_set, 2953 inv->dlg->pool, res_msg); 2954 2955 /* Recurse to alternate targets if application allows us */ 2956 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) 2957 { 2958 /* Recursion fails, terminate session now */ 2959 goto terminate_session; 2960 } 2961 2962 /* Done */ 2963 } 2964 2965 } else if ((tsx->status_code==401 || tsx->status_code==407) && 2966 !inv->cancelling) 2967 { 2968 2969 /* Handle authentication failure: 2970 * Resend the request with Authorization header. 2971 */ 2972 pjsip_tx_data *tdata; 2973 2974 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess, 2975 e->body.tsx_state.src.rdata, 2976 tsx->last_tx, 2977 &tdata); 2978 2979 if (status != PJ_SUCCESS) { 2980 2981 /* Does not have proper credentials. If we are currently 2982 * recursing, try the next target. Otherwise end the session. 2983 */ 2984 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) 2985 { 2986 /* Recursion fails, terminate session now */ 2987 goto terminate_session; 2988 } 2989 2990 } else { 2991 2992 /* Restart session. */ 2993 pjsip_inv_uac_restart(inv, PJ_FALSE); 2994 2995 /* Send the request. */ 2996 status = pjsip_inv_send_msg(inv, tdata); 2997 } 2998 2999 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) { 3000 /* Global error */ 3001 goto terminate_session; 3002 3003 } else { 3004 /* See if we have alternate target to try */ 3005 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) { 3006 /* Recursion fails, terminate session now */ 3007 goto terminate_session; 3008 } 3009 } 3010 return; 3011 3012 terminate_session: 3013 inv_set_cause(inv, tsx->status_code, &tsx->status_text); 3014 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 3015 } 3016 3017 2676 3018 /* 2677 3019 * State CALLING is after sending initial INVITE request but before … … 2736 3078 e->body.tsx_state.src.rdata); 2737 3079 2738 } else if ((tsx->status_code==401 || tsx->status_code==407) &&2739 !inv->cancelling)2740 {2741 2742 /* Handle authentication failure:2743 * Resend the request with Authorization header.2744 */2745 pjsip_tx_data *tdata;2746 2747 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,2748 e->body.tsx_state.src.rdata,2749 tsx->last_tx,2750 &tdata);2751 2752 if (status != PJ_SUCCESS) {2753 2754 /* Does not have proper credentials.2755 * End the session.2756 */2757 inv_set_cause(inv, tsx->status_code, &tsx->status_text);2758 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);2759 2760 } else {2761 2762 /* Restart session. */2763 inv->state = PJSIP_INV_STATE_NULL;2764 inv->invite_tsx = NULL;2765 if (inv->last_answer) {2766 pjsip_tx_data_dec_ref(inv->last_answer);2767 inv->last_answer = NULL;2768 }2769 2770 /* Send the request. */2771 status = pjsip_inv_send_msg(inv, tdata);2772 }2773 2774 3080 } else { 2775 2776 inv_set_cause(inv, tsx->status_code, &tsx->status_text); 2777 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 2778 3081 handle_uac_call_rejection(inv, e); 2779 3082 } 2780 3083 break; … … 2942 3245 e->body.tsx_state.src.rdata); 2943 3246 } 3247 3248 } else if (tsx->role == PJSIP_ROLE_UAC) { 3249 3250 handle_uac_call_rejection(inv, e); 2944 3251 2945 3252 } else { -
pjproject/trunk/pjsip/src/pjsip/sip_dialog.c
r2315 r2370 92 92 goto on_error; 93 93 94 pjsip_target_set_init(&dlg->target_set); 94 95 95 96 *p_dlg = dlg; … … 182 183 pj_list_init(&uri->header_param); 183 184 } 185 186 /* Add target to the target set */ 187 pjsip_target_set_add_uri(&dlg->target_set, dlg->pool, dlg->target, 0); 184 188 185 189 /* Init local info. */ -
pjproject/trunk/pjsip/src/pjsip/sip_util.c
r2103 r2370 49 49 static pj_str_t str_TEXT = { "text", 4}, 50 50 str_PLAIN = { "plain", 5 }; 51 52 /* Add URI to target-set */ 53 PJ_DEF(pj_status_t) pjsip_target_set_add_uri( pjsip_target_set *tset, 54 pj_pool_t *pool, 55 const pjsip_uri *uri, 56 int q1000) 57 { 58 pjsip_target *t, *pos = NULL; 59 60 PJ_ASSERT_RETURN(tset && pool && uri, PJ_EINVAL); 61 62 /* Set q-value to 1 if it is not set */ 63 if (q1000 <= 0) 64 q1000 = 1000; 65 66 /* Scan all the elements to see for duplicates, and at the same time 67 * get the position where the new element should be inserted to 68 * based on the q-value. 69 */ 70 t = tset->head.next; 71 while (t != &tset->head) { 72 if (pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, t->uri, uri)==PJ_SUCCESS) 73 return PJ_EEXISTS; 74 if (pos==NULL && t->q1000 < q1000) 75 pos = t; 76 t = t->next; 77 } 78 79 /* Create new element */ 80 t = PJ_POOL_ZALLOC_T(pool, pjsip_target); 81 t->uri = pjsip_uri_clone(pool, uri); 82 t->q1000 = q1000; 83 84 /* Insert */ 85 if (pos == NULL) 86 pj_list_push_back(&tset->head, t); 87 else 88 pj_list_insert_before(pos, t); 89 90 /* Set current target if this is the first URI */ 91 if (tset->current == NULL) 92 tset->current = t; 93 94 return PJ_SUCCESS; 95 } 96 97 /* Add URI's in the Contact header in the message to target-set */ 98 PJ_DEF(pj_status_t) pjsip_target_set_add_from_msg( pjsip_target_set *tset, 99 pj_pool_t *pool, 100 const pjsip_msg *msg) 101 { 102 const pjsip_hdr *hdr; 103 unsigned added = 0; 104 105 PJ_ASSERT_RETURN(tset && pool && msg, PJ_EINVAL); 106 107 /* Scan for Contact headers and add the URI */ 108 hdr = msg->hdr.next; 109 while (hdr != &msg->hdr) { 110 if (hdr->type == PJSIP_H_CONTACT) { 111 const pjsip_contact_hdr *cn_hdr = (const pjsip_contact_hdr*)hdr; 112 113 if (!cn_hdr->star) { 114 pj_status_t rc; 115 rc = pjsip_target_set_add_uri(tset, pool, cn_hdr->uri, 116 cn_hdr->q1000); 117 if (rc == PJ_SUCCESS) 118 ++added; 119 } 120 } 121 hdr = hdr->next; 122 } 123 124 return added ? PJ_SUCCESS : PJ_EEXISTS; 125 } 126 127 128 /* Get next target, if any */ 129 PJ_DEF(pjsip_target*) pjsip_target_set_get_next(const pjsip_target_set *tset) 130 { 131 const pjsip_target *t, *next = NULL; 132 133 t = tset->head.next; 134 while (t != &tset->head) { 135 if (PJSIP_IS_STATUS_IN_CLASS(t->code, 200)) { 136 /* No more target since one target has been successful */ 137 return NULL; 138 } 139 if (PJSIP_IS_STATUS_IN_CLASS(t->code, 600)) { 140 /* No more target since one target returned global error */ 141 return NULL; 142 } 143 if (t->code==0 && next==NULL) { 144 /* This would be the next target as long as we don't find 145 * targets with 2xx or 6xx status after this. 146 */ 147 next = t; 148 } 149 t = t->next; 150 } 151 152 return (pjsip_target*)next; 153 } 154 155 156 /* Set current target */ 157 PJ_DEF(pj_status_t) pjsip_target_set_set_current( pjsip_target_set *tset, 158 pjsip_target *target) 159 { 160 PJ_ASSERT_RETURN(tset && target, PJ_EINVAL); 161 PJ_ASSERT_RETURN(pj_list_find_node(tset, target) != NULL, PJ_ENOTFOUND); 162 163 tset->current = target; 164 165 return PJ_SUCCESS; 166 } 167 168 169 /* Assign status to a target */ 170 PJ_DEF(pj_status_t) pjsip_target_assign_status( pjsip_target *target, 171 pj_pool_t *pool, 172 int status_code, 173 const pj_str_t *reason) 174 { 175 PJ_ASSERT_RETURN(target && pool && status_code && reason, PJ_EINVAL); 176 177 target->code = status_code; 178 pj_strdup(pool, &target->reason, reason); 179 180 return PJ_SUCCESS; 181 } 182 183 51 184 52 185 /* -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
r2315 r2370 65 65 pjsip_transaction *tsx, 66 66 pjsip_event *e); 67 68 /* 69 * Redirection handler. 70 */ 71 static void pjsua_call_on_redirected(pjsip_inv_session *inv, 72 const pjsip_uri *target, 73 pjsip_redirect_op *cmd, 74 const pjsip_event *e); 67 75 68 76 … … 157 165 inv_cb.on_create_offer = &pjsua_call_on_create_offer; 158 166 inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed; 159 167 inv_cb.on_redirected = &pjsua_call_on_redirected; 160 168 161 169 /* Initialize invite session module: */ … … 1431 1439 1432 1440 return PJ_SUCCESS; 1441 } 1442 1443 1444 /* 1445 * Accept or reject redirection. 1446 */ 1447 PJ_DEF(pj_status_t) pjsua_call_process_redirect( pjsua_call_id call_id, 1448 pjsip_redirect_op cmd) 1449 { 1450 pjsua_call *call; 1451 pjsip_dialog *dlg; 1452 pj_status_t status; 1453 1454 PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 1455 PJ_EINVAL); 1456 1457 status = acquire_call("pjsua_call_process_redirect()", call_id, 1458 &call, &dlg); 1459 if (status != PJ_SUCCESS) 1460 return status; 1461 1462 status = pjsip_inv_process_redirect(call->inv, cmd, NULL); 1463 1464 pjsip_dlg_dec_lock(dlg); 1465 1466 return status; 1433 1467 } 1434 1468 … … 2828 2862 if (call->res_time.sec == 0) 2829 2863 pj_gettimeofday(&call->res_time); 2830 if (e->body.tsx_state.tsx->status_code > call->last_code) { 2864 if (e->type == PJSIP_EVENT_TSX_STATE && 2865 e->body.tsx_state.tsx->status_code > call->last_code) 2866 { 2831 2867 call->last_code = (pjsip_status_code) 2832 2868 e->body.tsx_state.tsx->status_code; 2833 2869 pj_strncpy(&call->last_text, 2834 2870 &e->body.tsx_state.tsx->status_text, 2871 sizeof(call->last_text_buf_)); 2872 } else { 2873 call->last_code = PJSIP_SC_REQUEST_TERMINATED; 2874 pj_strncpy(&call->last_text, 2875 pjsip_get_status_text(call->last_code), 2835 2876 sizeof(call->last_text_buf_)); 2836 2877 } … … 3771 3812 PJSUA_UNLOCK(); 3772 3813 } 3814 3815 3816 /* Redirection handler */ 3817 static void pjsua_call_on_redirected(pjsip_inv_session *inv, 3818 const pjsip_uri *target, 3819 pjsip_redirect_op *cmd, 3820 const pjsip_event *e) 3821 { 3822 pjsua_call *call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id]; 3823 3824 PJSUA_LOCK(); 3825 3826 if (pjsua_var.ua_cfg.cb.on_call_redirected) { 3827 (*pjsua_var.ua_cfg.cb.on_call_redirected)(call->index, target, cmd, e); 3828 } else { 3829 PJ_LOG(4,(THIS_FILE, "Unhandled redirection for call %d " 3830 "(callback not implemented by application). Disconnecting " 3831 "call.", 3832 call->index)); 3833 *cmd = PJSIP_REDIRECT_STOP; 3834 } 3835 3836 PJSUA_UNLOCK(); 3837 } 3838
Note: See TracChangeset
for help on using the changeset viewer.