diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 241c96c5eee0527f365063451d18bb6379f10fb5..e8b387ca04f665d3a6918f6b284d1e489e447f19 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2062,7 +2062,9 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event) if (res) { ast_queue_control_data(chan, AST_CONTROL_TRANSFER, &message, sizeof(message)); - ao2_ref(chan, -1); + // leaving channel with Ref > 2 cause it is not destroyed during hangup + while (2 < ao2_ref(chan, 0)) + ao2_ref(chan, -1); } } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index ad83ca0927055147815cfa5222d0a602ba42f52c..ce35e6fa4443304be53b649fde50bd81754848ef 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -65,7 +65,7 @@ #define DEFAULT_MAX_SESSION 4 static int max_sessions_per_line = DEFAULT_MAX_SESSION_PER_LINE; static int max_sessions = DEFAULT_MAX_SESSION; -static int current_session_count = 0; // current number of active sessions +static int current_session_count = 0; // current number of active sessions /* Some forward declarations */ static void handle_session_begin(struct ast_sip_session *session); @@ -3354,6 +3354,24 @@ static int setup_outbound_invite_auth(pjsip_dialog *dlg) return status != PJ_SUCCESS ? -1 : 0; } +int get_line_calls (struct ast_endpoint_snapshot * endpoint_snapshot) +{ + int count = 0; + for (int num = 0; num < endpoint_snapshot->num_channels; num++) { + struct ast_channel_snapshot *snapshot = ast_channel_snapshot_get_latest(endpoint_snapshot->channel_ids[num]); + + if (!snapshot) { + continue; + } + + if( (strcmp(snapshot->dialplan->appl, "Dial") == 0) && (strcmp(snapshot->dialplan->context, "call_line") == 0) || + (strcmp(snapshot->dialplan->appl, "AppDial") == 0) && (strcmp(snapshot->dialplan->context, "incoming_calls") == 0)) + count++; + } + + return count; +} + struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, const char *location, const char *request_user, struct ast_stream_topology *req_topology) @@ -3386,10 +3404,14 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup); ast_assert(endpoint_snapshot != NULL); - if (endpoint_snapshot && endpoint_snapshot->num_channels >= max_sessions_per_line) { - ast_log(LOG_WARNING, "Max call per line limit exceeded [%d/%d]\n", endpoint_snapshot->num_channels, max_sessions_per_line); + + int line_calls = get_line_calls(endpoint_snapshot); + + if (line_calls >= max_sessions_per_line) { + ast_log(LOG_WARNING, "Max call per line limit exceeded [%d/%d]\n", line_calls, max_sessions_per_line); SCOPE_EXIT_RTN_VALUE(NULL, "Max call per line limit exceeded\n"); - } else if (current_session_count >= max_sessions) { + } else if (((current_session_count >= max_sessions) && (ast_active_calls() != 3)) || + ((current_session_count >= max_sessions) && (ast_active_channels() >= 7))) { ast_log(LOG_WARNING, "Max call limit exceeded [%d/%d]\n", current_session_count, max_sessions); SCOPE_EXIT_RTN_VALUE(NULL, "Max call limit exceeded\n"); } @@ -3492,7 +3514,6 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint /* Avoid unnecessary ref manipulation to return a session */ ret_session = session; session = NULL; - current_session_count++; SCOPE_EXIT_RTN_VALUE(ret_session); } @@ -3575,7 +3596,6 @@ void ast_sip_session_terminate(struct ast_sip_session *session, int response) } break; } - current_session_count--; SCOPE_EXIT_RTN(); } @@ -4125,15 +4145,18 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup); ast_assert(endpoint_snapshot != NULL); - if (endpoint_snapshot && endpoint_snapshot->num_channels >= max_sessions_per_line) { - ast_log(LOG_WARNING, "Max call per line limit exceeded [%d/%d]\n", endpoint_snapshot->num_channels, max_sessions_per_line); + + int line_calls = get_line_calls(endpoint_snapshot); + + if (line_calls >= max_sessions_per_line) { + ast_log(LOG_WARNING, "Max call per line limit exceeded [%d/%d]\n", line_calls, max_sessions_per_line); /* Dialog's lock and reference are removed in new_invite_initial_answer */ if (!new_invite_initial_answer(inv_session, rdata, 486, 486, PJ_FALSE)) { /* Terminate the session if it wasn't done in the answer */ pjsip_inv_terminate(inv_session, 486, PJ_FALSE); } SCOPE_EXIT_RTN("Max call per line limit exceeded\n"); - } else if (current_session_count >= max_sessions) { + } else if ((current_session_count == max_sessions) || (ast_active_calls() >= max_sessions)) { ast_log(LOG_WARNING, "Max call limit exceeded [%d/%d]\n", current_session_count, max_sessions); /* Dialog's lock and reference are removed in new_invite_initial_answer */ if (!new_invite_initial_answer(inv_session, rdata, 486, 486, PJ_FALSE)) { @@ -4198,7 +4221,6 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) * be done before this. */ pjsip_dlg_dec_lock(inv_session->dlg); - current_session_count++; SCOPE_EXIT("Request: %s Session: %s\n", req_uri, ast_sip_session_get_name(session)); ao2_ref(session, -1); } @@ -4493,6 +4515,7 @@ static void handle_session_begin(struct ast_sip_session *session) { struct ast_sip_session_supplement *iter; + current_session_count++; AST_LIST_TRAVERSE(&session->supplements, iter, next) { if (iter->session_begin) { iter->session_begin(session); @@ -4503,7 +4526,6 @@ static void handle_session_begin(struct ast_sip_session *session) static void handle_session_destroy(struct ast_sip_session *session) { struct ast_sip_session_supplement *iter; - AST_LIST_TRAVERSE(&session->supplements, iter, next) { if (iter->session_destroy) { iter->session_destroy(session); @@ -4515,6 +4537,8 @@ static void handle_session_end(struct ast_sip_session *session) { struct ast_sip_session_supplement *iter; + if (current_session_count) + current_session_count--; /* Session is dead. Notify the supplements. */ AST_LIST_TRAVERSE(&session->supplements, iter, next) { if (iter->session_end) {