Пример #1
0
static void set_cause_code(struct respoke_session *session, enum respoke_status status)
{
	struct ast_control_pvt_cause_code *cause_code;
	int size;
	const char *cause = respoke_status_to_str(status);

	/* size of the cause = sizeof + "RESPOKE " + cause */
	size = sizeof(*cause_code) + 9 + strlen(cause);
	cause_code = ast_alloca(size);
	memset(cause_code, 0, size);

	ast_copy_string(cause_code->chan_name,
			ast_channel_name(session->channel), AST_CHANNEL_NAME);
	snprintf(cause_code->code, size - sizeof(*cause_code) + 1, "RESPOKE %s", cause);

	cause_code->ast_cause = hangup_reason_to_cause(status);
	ast_queue_control_data(session->channel, AST_CONTROL_PVT_CAUSE_CODE,
			       cause_code, size);
	ast_channel_hangupcause_hash_set(session->channel, cause_code, size);
}
Пример #2
0
/*! \brief Task for reacting to T.38 control frame */
static int t38_interpret_parameters(void *obj)
{
	RAII_VAR(struct t38_parameters_task_data *, data, obj, ao2_cleanup);
	const struct ast_control_t38_parameters *parameters = data->frame->data.ptr;
	struct t38_state *state = t38_state_get_or_alloc(data->session);
	RAII_VAR(struct ast_sip_session_media *, session_media, ao2_find(data->session->media, "image", OBJ_KEY), ao2_cleanup);

	/* Without session media or state we can't interpret parameters */
	if (!session_media || !state) {
		return 0;
	}

	switch (parameters->request_response) {
	case AST_T38_NEGOTIATED:
	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
		/* Negotiation can not take place without a valid max_ifp value. */
		if (!parameters->max_ifp) {
			if (data->session->t38state == T38_PEER_REINVITE) {
				t38_change_state(data->session, session_media, state, T38_REJECTED);
				ast_sip_session_resume_reinvite(data->session);
			} else if (data->session->t38state == T38_ENABLED) {
				t38_change_state(data->session, session_media, state, T38_DISABLED);
				ast_sip_session_refresh(data->session, NULL, NULL, NULL,
					AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
			}
			break;
		} else if (data->session->t38state == T38_PEER_REINVITE) {
			state->our_parms = *parameters;
			/* modify our parameters to conform to the peer's parameters,
			 * based on the rules in the ITU T.38 recommendation
			 */
			if (!state->their_parms.fill_bit_removal) {
				state->our_parms.fill_bit_removal = 0;
			}
			if (!state->their_parms.transcoding_mmr) {
				state->our_parms.transcoding_mmr = 0;
			}
			if (!state->their_parms.transcoding_jbig) {
				state->our_parms.transcoding_jbig = 0;
			}
			state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
			state->our_parms.rate_management = state->their_parms.rate_management;
			ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
			t38_change_state(data->session, session_media, state, T38_ENABLED);
			ast_sip_session_resume_reinvite(data->session);
		} else if (data->session->t38state != T38_ENABLED) {
			if (t38_initialize_session(data->session, session_media)) {
				break;
			}
			state->our_parms = *parameters;
			ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
			t38_change_state(data->session, session_media, state, T38_LOCAL_REINVITE);
			ast_sip_session_refresh(data->session, NULL, t38_reinvite_sdp_cb, t38_reinvite_response_cb,
				AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
		}
		break;
	case AST_T38_TERMINATED:
	case AST_T38_REFUSED:
	case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
		if (data->session->t38state == T38_PEER_REINVITE) {
			t38_change_state(data->session, session_media, state, T38_REJECTED);
			ast_sip_session_resume_reinvite(data->session);
		} else if (data->session->t38state == T38_ENABLED) {
			t38_change_state(data->session, session_media, state, T38_DISABLED);
			ast_sip_session_refresh(data->session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
		}
		break;
	case AST_T38_REQUEST_PARMS: {		/* Application wants remote's parameters re-sent */
		struct ast_control_t38_parameters parameters = state->their_parms;

		if (data->session->t38state == T38_PEER_REINVITE) {
			parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
			parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
			ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
		}
		break;
	}
	default:
		break;
	}

	return 0;
}
Пример #3
0
/*! \brief Helper function for changing the T.38 state */
static void t38_change_state(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
	struct t38_state *state, enum ast_sip_session_t38state new_state)
{
	enum ast_sip_session_t38state old_state = session->t38state;
	struct ast_control_t38_parameters parameters = { .request_response = 0, };
	pj_time_val delay = { .sec = T38_AUTOMATIC_REJECTION_SECONDS };

	if (old_state == new_state) {
		return;
	}

	session->t38state = new_state;
	ast_debug(2, "T.38 state changed to '%u' from '%u' on channel '%s'\n",
		new_state, old_state,
		session->channel ? ast_channel_name(session->channel) : "<gone>");

	if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &state->timer)) {
		ast_debug(2, "Automatic T.38 rejection on channel '%s' terminated\n",
			session->channel ? ast_channel_name(session->channel) : "<gone>");
		ao2_ref(session, -1);
	}

	if (!session->channel) {
		return;
	}

	switch (new_state) {
	case T38_PEER_REINVITE:
		ao2_ref(session, +1);
		if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &state->timer, &delay) != PJ_SUCCESS) {
			ast_log(LOG_WARNING, "Scheduling of automatic T.38 rejection for channel '%s' failed\n",
				ast_channel_name(session->channel));
			ao2_ref(session, -1);
		}
		parameters = state->their_parms;
		parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
		parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
		ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
		break;
	case T38_ENABLED:
		parameters = state->their_parms;
		parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
		parameters.request_response = AST_T38_NEGOTIATED;
		ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
		break;
	case T38_REJECTED:
	case T38_DISABLED:
		if (old_state == T38_ENABLED) {
			parameters.request_response = AST_T38_TERMINATED;
		} else if (old_state == T38_LOCAL_REINVITE) {
			parameters.request_response = AST_T38_REFUSED;
		}
		break;
	case T38_LOCAL_REINVITE:
		/* wait until we get a peer response before responding to local reinvite */
		break;
	case T38_MAX_ENUM:
		/* Well, that shouldn't happen */
		ast_assert(0);
		break;
	}

	if (parameters.request_response) {
		ast_queue_control_data(session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
	}
}

/*! \brief Task function which rejects a T.38 re-invite and resumes handling it */
static int t38_automatic_reject(void *obj)
{
	RAII_VAR(struct ast_sip_session *, session, obj, ao2_cleanup);
	RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup);
	RAII_VAR(struct ast_sip_session_media *, session_media, ao2_find(session->media, "image", OBJ_KEY), ao2_cleanup);

	if (!datastore) {
		return 0;
	}

	ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n",
		session->channel ? ast_channel_name(session->channel) : "<gone>");

	t38_change_state(session, session_media, datastore->data, T38_REJECTED);
	ast_sip_session_resume_reinvite(session);

	return 0;
}