diff --git a/deps/5249.diff b/deps/5249.diff new file mode 100644 index 00000000..087e040e --- /dev/null +++ b/deps/5249.diff @@ -0,0 +1,517 @@ +Index: pjnath/include/pjnath/ice_strans.h +=================================================================== +--- pjnath/include/pjnath/ice_strans.h (revision 5249) ++++ pjnath/include/pjnath/ice_strans.h (working copy) +@@ -132,6 +132,52 @@ + + } pj_ice_strans_op; + ++ ++/** ++ * ICE stream transport's state. ++ */ ++typedef enum pj_ice_strans_state ++{ ++ /** ++ * ICE stream transport is not created. ++ */ ++ PJ_ICE_STRANS_STATE_NULL, ++ ++ /** ++ * ICE candidate gathering process is in progress. ++ */ ++ PJ_ICE_STRANS_STATE_INIT, ++ ++ /** ++ * ICE stream transport initialization/candidate gathering process is ++ * complete, ICE session may be created on this stream transport. ++ */ ++ PJ_ICE_STRANS_STATE_READY, ++ ++ /** ++ * New session has been created and the session is ready. ++ */ ++ PJ_ICE_STRANS_STATE_SESS_READY, ++ ++ /** ++ * ICE negotiation is in progress. ++ */ ++ PJ_ICE_STRANS_STATE_NEGO, ++ ++ /** ++ * ICE negotiation has completed successfully and media is ready ++ * to be used. ++ */ ++ PJ_ICE_STRANS_STATE_RUNNING, ++ ++ /** ++ * ICE negotiation has completed with failure. ++ */ ++ PJ_ICE_STRANS_STATE_FAILED ++ ++} pj_ice_strans_state; ++ ++ + /** + * This structure contains callbacks that will be called by the + * ICE stream transport. +@@ -167,6 +213,17 @@ + pj_ice_strans_op op, + pj_status_t status); + ++ /** ++ * Callback to report ICE state changes. ++ * ++ * @param ice_st The ICE stream transport. ++ * @param prev Previous state. ++ * @param curr Current state. ++ */ ++ void (*on_ice_state)(pj_ice_strans *ice_st, ++ pj_ice_strans_state prev, ++ pj_ice_strans_state curr); ++ + } pj_ice_strans_cb; + + +@@ -409,51 +466,6 @@ + } pj_ice_strans_cfg; + + +-/** +- * ICE stream transport's state. +- */ +-typedef enum pj_ice_strans_state +-{ +- /** +- * ICE stream transport is not created. +- */ +- PJ_ICE_STRANS_STATE_NULL, +- +- /** +- * ICE candidate gathering process is in progress. +- */ +- PJ_ICE_STRANS_STATE_INIT, +- +- /** +- * ICE stream transport initialization/candidate gathering process is +- * complete, ICE session may be created on this stream transport. +- */ +- PJ_ICE_STRANS_STATE_READY, +- +- /** +- * New session has been created and the session is ready. +- */ +- PJ_ICE_STRANS_STATE_SESS_READY, +- +- /** +- * ICE negotiation is in progress. +- */ +- PJ_ICE_STRANS_STATE_NEGO, +- +- /** +- * ICE negotiation has completed successfully and media is ready +- * to be used. +- */ +- PJ_ICE_STRANS_STATE_RUNNING, +- +- /** +- * ICE negotiation has completed with failure. +- */ +- PJ_ICE_STRANS_STATE_FAILED +- +-} pj_ice_strans_state; +- +- + /** + * Initialize ICE transport configuration with default values. + * +@@ -792,6 +804,26 @@ + unsigned comp_id); + + /** ++ * Retrieve the ICE session associated with this transport ++ * ++ * @param ice_st The ICE stream transport. ++ * ++ * @return The ICE session associated with this transport ++ */ ++PJ_DECL(pj_ice_sess*) ++pj_ice_strans_get_session(const pj_ice_strans *ice_st); ++ ++/** ++ * Retrieve the ICE start time ++ * ++ * @param ice_st The ICE stream transport. ++ * ++ * @return The ICE start time ++ */ ++PJ_DECL(pj_time_val) ++pj_ice_strans_get_start_time(const pj_ice_strans *ice_st); ++ ++/** + * Stop and destroy the ICE session inside this media transport. Application + * needs to call this function once the media session is over (the call has + * been disconnected). +Index: pjnath/src/pjnath/ice_strans.c +=================================================================== +--- pjnath/src/pjnath/ice_strans.c (revision 5249) ++++ pjnath/src/pjnath/ice_strans.c (working copy) +@@ -187,6 +187,19 @@ + }; + + ++/* Set ICE state*/ ++static void set_ice_state(pj_ice_strans *ice_st, pj_ice_strans_state state) ++{ ++ pj_ice_strans_state prev = ice_st->state; ++ ++ if (prev != state) { ++ ice_st->state = state; ++ if (ice_st->cb.on_ice_state) ++ (*ice_st->cb.on_ice_state)(ice_st, prev, state); ++ } ++} ++ ++ + /* Validate configuration */ + static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg) + { +@@ -638,7 +651,7 @@ + pj_pool_calloc(pool, comp_cnt, sizeof(pj_ice_strans_comp*)); + + /* Move state to candidate gathering */ +- ice_st->state = PJ_ICE_STRANS_STATE_INIT; ++ set_ice_state(ice_st, PJ_ICE_STRANS_STATE_INIT); + + /* Acquire initialization mutex to prevent callback to be + * called before we finish initialization. +@@ -795,7 +808,7 @@ + + /* All candidates have been gathered */ + ice_st->cb_called = PJ_TRUE; +- ice_st->state = PJ_ICE_STRANS_STATE_READY; ++ set_ice_state(ice_st, PJ_ICE_STRANS_STATE_READY); + if (ice_st->cb.on_ice_complete) + (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_INIT, + PJ_SUCCESS); +@@ -948,7 +961,7 @@ + } + + /* ICE session is ready for negotiation */ +- ice_st->state = PJ_ICE_STRANS_STATE_SESS_READY; ++ set_ice_state(ice_st, PJ_ICE_STRANS_STATE_SESS_READY); + + return PJ_SUCCESS; + +@@ -1171,7 +1184,7 @@ + return status; + } + +- ice_st->state = PJ_ICE_STRANS_STATE_NEGO; ++ set_ice_state(ice_st, PJ_ICE_STRANS_STATE_NEGO); + return status; + } + +@@ -1192,6 +1205,25 @@ + } + + /* ++ * Get ICE session. ++ */ ++PJ_DEF(pj_ice_sess*) ++pj_ice_strans_get_session(const pj_ice_strans *ice_st) ++{ ++ return ice_st->ice; ++} ++ ++/* ++ * Get ICE start time. ++ */ ++PJ_DEF(pj_time_val) ++pj_ice_strans_get_start_time(const pj_ice_strans *ice_st) ++{ ++ ++ return ice_st->start_time; ++} ++ ++/* + * Stop ICE! + */ + PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st) +@@ -1209,7 +1241,7 @@ + ice_st->ice = NULL; + } + +- ice_st->state = PJ_ICE_STRANS_STATE_INIT; ++ set_ice_state(ice_st, PJ_ICE_STRANS_STATE_INIT); + + pj_grp_lock_release(ice_st->grp_lock); + +@@ -1387,8 +1419,8 @@ + } + } + +- ice_st->state = (status==PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING : +- PJ_ICE_STRANS_STATE_FAILED; ++ set_ice_state(ice_st, (status==PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING : ++ PJ_ICE_STRANS_STATE_FAILED); + + pj_log_push_indent(); + (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION, +Index: pjsip/include/pjsip/sip_msg.h +=================================================================== +--- pjsip/include/pjsip/sip_msg.h (revision 5249) ++++ pjsip/include/pjsip/sip_msg.h (working copy) +@@ -673,6 +673,21 @@ + }; + + /** ++ * General purpose function to print a SIP message body. ++ * Uses the appropriate internal functions to print the string representation ++ * of a SIP message body. It sets the output buffer to a statically allocated ++ * buffer, so the caller is responsible to copy it. ++ * ++ * @param msg_body The message body. ++ * @param buf Pointer to get the result buffer (statically allocated). ++ * @param size The size of the buffer. ++ * ++ * @return The length copied to the buffer, or -1. ++ */ ++PJ_DECL(int) pjsip_print_body( pjsip_msg_body *msg_body, ++ char **buf, int *len); ++ ++/** + * General purpose function to textual data in a SIP body. Attach this function + * in a SIP message body only if the data in pjsip_msg_body is a textual + * message ready to be embedded in a SIP message. If the data in the message +@@ -892,6 +907,20 @@ + PJ_DECL(void*) pjsip_msg_find_remove_hdr( pjsip_msg *msg, + pjsip_hdr_e hdr, void *start); + ++/** ++ * Find and remove a header in the message. ++ * ++ * @param msg The message. ++ * @param name The header name to find. ++ * @param start The first header field where the search should begin, ++ * or NULL to search from the first header in the message. ++ * ++ * @return The header field, or NULL if not found. ++ */ ++PJ_DECL(void*) pjsip_msg_find_remove_hdr_by_name( pjsip_msg *msg, ++ pj_str_t *name, ++ void *start); ++ + /** + * Add a header to the message, putting it last in the header list. + * +Index: pjsip/include/pjsip-simple/evsub.h +=================================================================== +--- pjsip/include/pjsip-simple/evsub.h (revision 5249) ++++ pjsip/include/pjsip-simple/evsub.h (working copy) +@@ -490,7 +490,17 @@ + PJ_DECL(void*) pjsip_evsub_get_mod_data( pjsip_evsub *sub, unsigned mod_id ); + + ++/* Update evbsub internal refresh_time with the given interval */ ++PJ_DECL(void) pjsip_evsub_update_expires( pjsip_evsub *sub, ++ pj_uint32_t interval ); + ++ ++/* Set the specified timer (UAC or UAS) to the specified time */ ++PJ_DECL(void) pjsip_evsub_set_timer( pjsip_evsub *sub, ++ int timer_id, ++ pj_int32_t seconds ); ++ ++ + PJ_END_DECL + + /** +Index: pjsip/src/pjsip/sip_msg.c +=================================================================== +--- pjsip/src/pjsip/sip_msg.c (revision 5249) ++++ pjsip/src/pjsip/sip_msg.c (working copy) +@@ -395,6 +395,17 @@ + return hdr; + } + ++PJ_DEF(void*) pjsip_msg_find_remove_hdr_by_name( pjsip_msg *msg, ++ pj_str_t *name, ++ void *start) ++{ ++ pjsip_hdr *hdr = (pjsip_hdr*) pjsip_msg_find_hdr_by_name(msg, name, start); ++ if (hdr) { ++ pj_list_erase(hdr); ++ } ++ return hdr; ++} ++ + PJ_DEF(pj_ssize_t) pjsip_msg_print( const pjsip_msg *msg, + char *buf, pj_size_t size) + { +@@ -2133,6 +2144,20 @@ + /* + * Message body manipulations. + */ ++PJ_DEF(int) pjsip_print_body(pjsip_msg_body *msg_body, char **buf, int *len) ++{ ++ static char s_buf[PJSIP_MAX_PKT_LEN]; ++ int res; ++ ++ res = (*msg_body->print_body)(msg_body, s_buf, PJSIP_MAX_PKT_LEN); ++ if (res < 0) { ++ return -1; ++ } ++ *buf = s_buf; ++ *len = res; ++ return 0; ++} ++ + PJ_DEF(int) pjsip_print_text_body(pjsip_msg_body *msg_body, char *buf, pj_size_t size) + { + if (size < msg_body->len) +Index: pjsip/src/pjsip-simple/evsub.c +=================================================================== +--- pjsip/src/pjsip-simple/evsub.c (revision 5249) ++++ pjsip/src/pjsip-simple/evsub.c (working copy) +@@ -492,7 +492,12 @@ + sub->refresh_time.sec += interval; + } + ++PJ_DEF(void) pjsip_evsub_update_expires( pjsip_evsub *sub, pj_uint32_t interval ) ++{ ++ update_expires(sub, interval); ++} + ++ + /* + * Schedule timer. + */ +@@ -526,7 +531,13 @@ + } + } + ++PJ_DEF(void) pjsip_evsub_set_timer( pjsip_evsub *sub, int timer_id, ++ pj_int32_t seconds) ++{ ++ set_timer(sub, timer_id, seconds); ++} + ++ + /* + * Destructor. + */ +Index: pjsip/src/pjsip-simple/evsub_msg.c +=================================================================== +--- pjsip/src/pjsip-simple/evsub_msg.c (revision 5249) ++++ pjsip/src/pjsip-simple/evsub_msg.c (working copy) +@@ -291,6 +291,44 @@ + } + + /* ++ * Parse Allow-Events header. ++ */ ++static pjsip_hdr* parse_hdr_allow_events(pjsip_parse_ctx *ctx) ++{ ++ pjsip_allow_events_hdr *allow_events = ++ pjsip_allow_events_hdr_create(ctx->pool); ++ const pjsip_parser_const_t *pc = pjsip_parser_const(); ++ pj_scanner *scanner = ctx->scanner; ++ ++ /* Some header fields allow empty elements in the value: ++ * Accept, Allow, Supported ++ */ ++ if (pj_scan_is_eof(scanner) || ++ *scanner->curptr == '\r' || *scanner->curptr == '\n') ++ { ++ goto end; ++ } ++ ++ pj_scan_get( scanner, &pc->pjsip_NOT_COMMA_OR_NEWLINE, ++ &allow_events->values[0]); ++ allow_events->count++; ++ ++ while (*scanner->curptr == ',') { ++ pj_scan_get_char(scanner); ++ pj_scan_get( scanner, &pc->pjsip_NOT_COMMA_OR_NEWLINE, ++ &allow_events->values[allow_events->count]); ++ allow_events->count++; ++ ++ if (allow_events->count >= PJSIP_MAX_ALLOW_EVENTS) ++ break; ++ } ++ ++end: ++ pjsip_parse_end_hdr_imp(scanner); ++ return (pjsip_hdr*)allow_events; ++} ++ ++/* + * Register header parsers. + */ + PJ_DEF(void) pjsip_evsub_init_parser(void) +@@ -300,5 +338,8 @@ + + pjsip_register_hdr_parser( "Subscription-State", NULL, + &parse_hdr_sub_state); ++ ++ pjsip_register_hdr_parser( "Allow-Events", NULL, ++ &parse_hdr_allow_events); + } + +Index: pjsip/src/pjsip-ua/sip_inv.c +=================================================================== +--- pjsip/src/pjsip-ua/sip_inv.c (revision 5249) ++++ pjsip/src/pjsip-ua/sip_inv.c (working copy) +@@ -1935,6 +1935,19 @@ + return PJMEDIA_SDP_EINSDP; + } + ++ /* Only accept SDP in INVITE, UPDATE and ACK requests, 18x (reliable) and 183 provisional responses ++ * and 200 final response. ++ */ ++ if (!(msg->type == PJSIP_REQUEST_MSG && msg->line.req.method.id == PJSIP_INVITE_METHOD) && ++ !(msg->type == PJSIP_REQUEST_MSG && msg->line.req.method.id == PJSIP_ACK_METHOD) && ++ !(msg->type == PJSIP_REQUEST_MSG && pjsip_method_cmp(&msg->line.req.method, &pjsip_update_method)==0) && ++ !(msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/10==18 && pjsip_100rel_is_reliable(rdata)) && ++ !(msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code == 183) && ++ !(msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code == 200)) { ++ PJ_LOG(4,(inv->obj_name, "ignored SDP body")); ++ return PJ_SUCCESS; ++ } ++ + /* Get/attach invite session's transaction data */ + tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id]; + if (tsx_inv_data == NULL) { +@@ -2144,6 +2157,11 @@ + { + status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov, inv->neg, + local_sdp); ++ } else if (pjmedia_sdp_neg_get_state(inv->neg)== ++ PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) ++ { ++ /* Go forward with our local offer */ ++ status = PJ_SUCCESS; + } else { + + /* Can not specify local SDP at this state. */ +@@ -3875,8 +3893,9 @@ + if (inv->state != PJSIP_INV_STATE_DISCONNECTED && + ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST && + tsx->method.id != PJSIP_CANCEL_METHOD) || +- tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT || +- tsx->status_code == PJSIP_SC_TSX_TIMEOUT)) ++ (inv->state != PJSIP_INV_STATE_CONFIRMED && ++ (tsx->status_code == PJSIP_SC_TSX_TIMEOUT || ++ tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)))) + { + pjsip_tx_data *bye; + pj_status_t status; +@@ -4715,6 +4734,7 @@ + * Handle strandled incoming CANCEL or CANCEL for re-INVITE + */ + inv_respond_incoming_cancel(inv, tsx, e); ++ + } + else if (tsx->method.id == PJSIP_INVITE_METHOD && + tsx->role == PJSIP_ROLE_UAS)