/* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_get_local_candidates(tsip_dialog_invite_t* self, tsip_message_t* message) { if(self->supported.ice){ tsk_bool_t use_ice = tsk_false; // "action->media.type" will be defined for locally initiated media update tmedia_type_t new_media = TSIP_DIALOG(self)->curr_action ? TSIP_DIALOG(self)->curr_action->media.type : tmedia_none; if(message && TSIP_MESSAGE_HAS_CONTENT(message) && tsk_striequals("application/sdp", TSIP_MESSAGE_CONTENT_TYPE(message))){ // If this code is called this means that we are the "answerer" // only gets the candidates if ICE is enabled and the remote peer supports ICE tsdp_message_t* sdp_ro; const tsdp_header_M_t* M; int index; if(!(sdp_ro = tsdp_message_parse(TSIP_MESSAGE_CONTENT_DATA(message), TSIP_MESSAGE_CONTENT_DATA_LENGTH(message)))){ TSK_DEBUG_ERROR("Failed to parse remote sdp message"); return tsk_false; } index = 0; while((M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp_ro, tsdp_htype_M, index++))){ if(!tsdp_header_M_findA(M, "candidate")){ use_ice = tsk_false; // do not use ICE is at least on media is ICE-less (e.g. MSRP) break; } use_ice = tsk_true; // only use ICE if there is a least one media line } new_media = tmedia_type_from_sdp(sdp_ro); TSK_OBJECT_SAFE_FREE(sdp_ro); } else if(!message){ // we are the "offerer" -> use ICE only for audio or video medias (ignore ice for MSRP) use_ice = (new_media & tmedia_audio) || (new_media & tmedia_video); } if(use_ice){ if(!self->ice.ctx_audio && !self->ice.ctx_video){ // First time return tsk_true; } else{ if(self->ice.media_type != new_media){ return tsk_true; } return !tsip_dialog_invite_ice_got_local_candidates(self); } } } return tsk_false; }
int tsip_dialog_message_init(tsip_dialog_message_t *self) { //const tsk_param_t* param; /* Initialize the state machine. */ tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), /*======================= * === Started === */ // Started -> (send) -> Sending TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_sendMESSAGE, _fsm_state_Sending, tsip_dialog_message_Started_2_Sending_X_sendMESSAGE, "tsip_dialog_message_Started_2_Sending_X_sendMESSAGE"), // Started -> (receive) -> Receiving TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_receiveMESSAGE, _fsm_state_Receiving, tsip_dialog_message_Started_2_Receiving_X_recvMESSAGE, "tsip_dialog_message_Started_2_Receiving_X_recvMESSAGE"), // Started -> (Any) -> Started TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_message_Started_2_Started_X_any"), /*======================= * === Sending === */ // Sending -> (1xx) -> Sending TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_1xx, _fsm_state_Sending, tsip_dialog_message_Sending_2_Sending_X_1xx, "tsip_dialog_message_Sending_2_Sending_X_1xx"), // Sending -> (2xx) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_2xx, _fsm_state_Terminated, tsip_dialog_message_Sending_2_Terminated_X_2xx, "tsip_dialog_message_Sending_2_Terminated_X_2xx"), // Sending -> (401/407/421/494) -> Sending TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_401_407_421_494, _fsm_state_Sending, tsip_dialog_message_Sending_2_Sending_X_401_407_421_494, "tsip_dialog_message_Sending_2_Sending_X_401_407_421_494"), // Sending -> (300_to_699) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_message_Sending_2_Terminated_X_300_to_699, "tsip_dialog_message_Sending_2_Terminated_X_300_to_699"), // Sending -> (cancel) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_message_Sending_2_Terminated_X_cancel, "tsip_dialog_message_Sending_2_Terminated_X_cancel"), // Sending -> (shutdown) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_message_Sending_2_Terminated_X_shutdown"), // Sending -> (Any) -> Sending TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Sending, "tsip_dialog_message_Sending_2_Sending_X_any"), /*======================= * === Receiving === */ // Receiving -> (accept) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_accept, _fsm_state_Terminated, tsip_dialog_message_Receiving_2_Terminated_X_accept, "tsip_dialog_message_Receiving_2_Terminated_X_accept"), // Receiving -> (rejected) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_reject, _fsm_state_Terminated, tsip_dialog_message_Receiving_2_Terminated_X_reject, "tsip_dialog_message_Receiving_2_Terminated_X_reject"), // Receiving -> (Any) -> Receiving TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Receiving, "tsip_dialog_message_Receiving_2_Receiving_X_any"), /*======================= * === Any === */ // Any -> (transport error) -> Terminated TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_message_Any_2_Terminated_X_transportError, "tsip_dialog_message_Any_2_Terminated_X_transportError"), // Any -> (transport error) -> Terminated TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_message_Any_2_Terminated_X_Error, "tsip_dialog_message_Any_2_Terminated_X_Error"), TSK_FSM_ADD_NULL()); TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_message_event_callback); return 0; }
// Started -> (oINVITE) -> Started static int x0500_Current_2_Current_X_oINVITE(va_list *app) { int ret; tsip_dialog_invite_t *self; const tsip_action_t* action; const tsip_message_t *message; tmedia_type_t media_type; self = va_arg(*app, tsip_dialog_invite_t *); message = va_arg(*app, const tsip_message_t *); action = va_arg(*app, const tsip_action_t *); media_type = (action && action->media.type != tmedia_none) ? action->media.type : TSIP_DIALOG_GET_SS(self)->media.type; self->is_client = tsk_true; tsip_dialog_invite_ice_save_action(self, _fsm_action_oINVITE, action, message); // create ICE context if((ret = tsip_dialog_invite_ice_create_ctx(self, media_type))){ TSK_DEBUG_ERROR("tsip_dialog_invite_ice_create_ctx() failed"); return ret; } // Start ICE ret = tsip_dialog_invite_ice_start_ctx(self); // alert the user only if we are in initial state which means that it's not media update if(TSIP_DIALOG(self)->state == tsip_initial){ TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); } return ret; }
/** Timer manager callback. * * @param [in,out] self The owner of the signaled timer. * @param timer_id The identifier of the signaled timer. * * @return Zero if succeed and non-zero error code otherwise. **/ int tsip_dialog_subscribe_timer_callback(const tsip_dialog_subscribe_t* self, tsk_timer_id_t timer_id) { int ret = -1; if(self) { if(timer_id == self->timerrefresh.id){ tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_subscribe, tsk_null, tsk_null); ret = 0; } else if(timer_id == self->timershutdown.id){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_shutdown_timedout, tsk_null, tsk_null); } } return ret; }
/* Started -> (sendOPTIONS) -> Sending */ int tsip_dialog_options_Started_2_Sending_X_sendOPTIONS(va_list *app) { tsip_dialog_options_t *self; const tsip_action_t* action; self = va_arg(*app, tsip_dialog_options_t *); /*tsip_request_t *request =*/ va_arg(*app, tsip_request_t *); action = va_arg(*app, const tsip_action_t *); TSIP_DIALOG(self)->running = tsk_true; tsip_dialog_set_curr_action(TSIP_DIALOG(self), action); /* alert the user */ TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); return send_OPTIONS(self); }
static int tsip_dialog_invite_ice_callback(const tnet_ice_event_t *e) { int ret = 0; tsip_dialog_invite_t *dialog; TSK_DEBUG_INFO("ICE callback: %s", e->phrase); dialog = tsk_object_ref(TSK_OBJECT(e->userdata)); // Do not lock: caller is thread safe switch(e->type){ case tnet_ice_event_type_gathering_completed: case tnet_ice_event_type_conncheck_succeed: case tnet_ice_event_type_conncheck_failed: case tnet_ice_event_type_cancelled: { if(dialog->ice.last_action_id != tsk_fsm_state_none){ if(tsip_dialog_invite_ice_got_local_candidates(dialog)){ tsip_dialog_fsm_act(TSIP_DIALOG(dialog), dialog->ice.last_action_id, dialog->ice.last_message, dialog->ice.last_action); dialog->ice.last_action_id = tsk_fsm_state_none; } } if(dialog->ice.start_smgr){ ret = tsip_dialog_invite_msession_start(dialog); } break; } // fatal errors which discard ICE process case tnet_ice_event_type_gathering_host_candidates_failed: case tnet_ice_event_type_gathering_reflexive_candidates_failed: { if(dialog->ice.last_action_id != tsk_fsm_state_none){ tsip_dialog_fsm_act(TSIP_DIALOG(dialog), dialog->ice.last_action_id, dialog->ice.last_message, dialog->ice.last_action); dialog->ice.last_action_id = tsk_fsm_state_none; } break; } default: break; } TSK_OBJECT_SAFE_FREE(dialog); return ret; }
/* Outgoing -> (i2xx INVITE) -> Connected */ int c0000_Outgoing_2_Connected_X_i2xxINVITE(va_list *app) { int ret; tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); const tsip_response_t *r2xxINVITE = va_arg(*app, const tsip_response_t *); /* const tsip_action_t* action = */ va_arg(*app, const tsip_action_t *); /* Update the dialog state */ if((ret = tsip_dialog_update(TSIP_DIALOG(self), r2xxINVITE))){ return ret; } /* Process remote offer */ if((ret = tsip_dialog_invite_process_ro(self, r2xxINVITE))){ send_BYE(self); return ret; } else{ /* send ACK */ ret = send_ACK(self, r2xxINVITE); } /* Determine whether the remote party support UPDATE */ self->support_update = tsip_message_allowed(r2xxINVITE, "UPDATE"); /* Session Timers */ if(self->stimers.timer.timeout){ tsip_dialog_invite_stimers_handle(self, r2xxINVITE); } // starts ICE timers now that both parties received the "candidates" if(tsip_dialog_invite_ice_is_enabled(self)){ tsip_dialog_invite_ice_timers_set(self, (self->required.ice ? -1 : TSIP_DIALOG_INVITE_ICE_CONNCHECK_TIMEOUT)); } /* Alert the user (session) */ ret = TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, TSIP_RESPONSE_CODE(r2xxINVITE), TSIP_RESPONSE_PHRASE(r2xxINVITE), r2xxINVITE); /* Alert the user (dialog) */ ret = TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); if(self->is_transf){ ret = tsip_dialog_invite_notify_parent(self, r2xxINVITE); self->is_transf = tsk_false;//final response -> no longer need to notify the parent } /* MSRP File Transfer */ /*if(TSIP_DIALOG(self)->curr_action && ((TSIP_DIALOG(self)->curr_action->media.type & tmedia_msrp) == tmedia_msrp)){ // FIXME tmedia_session_mgr_send_file(self->msession_mgr, "C:\\avatar.png", TMEDIA_SESSION_SET_NULL()); }*/ return ret; }
/* Started -> (sendMESSAGE) -> Sending */ int tsip_dialog_message_Started_2_Sending_X_sendMESSAGE(va_list *app) { tsip_dialog_message_t *self; self = va_arg(*app, tsip_dialog_message_t *); TSIP_DIALOG(self)->running = tsk_true; return send_MESSAGE(self); }
int tsip_dialog_options_event_callback(const tsip_dialog_options_t *self, tsip_dialog_event_type_t type, const tsip_message_t *msg) { int ret = -1; switch(type) { case tsip_dialog_i_msg: { if(msg){ if(TSIP_MESSAGE_IS_RESPONSE(msg)){ if(TSIP_RESPONSE_IS_1XX(msg)){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_1xx, msg, tsk_null); } else if(TSIP_RESPONSE_IS_2XX(msg)){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_2xx, msg, tsk_null); } else if(TSIP_RESPONSE_CODE(msg) == 401 || TSIP_RESPONSE_CODE(msg) == 407 || TSIP_RESPONSE_CODE(msg) == 421 || TSIP_RESPONSE_CODE(msg) == 494){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, tsk_null); } else if(TSIP_RESPONSE_IS_3456(msg)){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_300_to_699, msg, tsk_null); } else{ /* should never happen */ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, tsk_null); } } else if (TSIP_REQUEST_IS_OPTIONS(msg)){ /* have been checked by dialog layer...but */ // REQUEST ==> Incoming OPTIONS ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_receiveOPTIONS, msg, tsk_null); } } break; } case tsip_dialog_canceled: { ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_cancel, msg, tsk_null); break; } case tsip_dialog_terminated: case tsip_dialog_timedout: case tsip_dialog_error: case tsip_dialog_transport_error: { ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); break; } } return ret; }
/** Initializes the dialog. * * @param [in,out] self The dialog to initialize. **/ int tsip_dialog_register_init(tsip_dialog_register_t *self) { // Initialize client side tsip_dialog_register_client_init(self); // initialize server side tsip_dialog_register_server_init(self); /* Initialize common side */ tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), /*======================= * === Any === */ // Any -> (hangup) -> InProgress TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_not_silent_hangup, _fsm_state_InProgress, tsip_dialog_register_Any_2_InProgress_X_hangup, "tsip_dialog_register_Any_2_InProgress_X_hangup"), // Any -> (silenthangup) -> Terminated TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_silent_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_Any_2_InProgress_X_silenthangup"), // Any -> (shutdown) -> InProgress TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_not_silent_shutdown, _fsm_state_InProgress, tsip_dialog_register_Any_2_InProgress_X_shutdown, "tsip_dialog_register_Any_2_InProgress_X_shutdown"), // Any -> (silentshutdown) -> Terminated TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_silent_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_Any_2_InProgress_X_silentshutdown"), // Any -> (shutdown timedout) -> Terminated TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_shutdown_timedout"), // Any -> (transport error) -> Terminated TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_register_Any_2_Terminated_X_transportError, "tsip_dialog_register_Any_2_Terminated_X_transportError"), // Any -> (error) -> Terminated TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_register_Any_2_Terminated_X_Error, "tsip_dialog_register_Any_2_Terminated_X_Error"), TSK_FSM_ADD_NULL()); /* Sets callback function */ TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_register_event_callback); /* Timers */ self->timerrefresh.id = TSK_INVALID_TIMER_ID; self->timerrefresh.timeout = TSIP_DIALOG(self)->expires; self->timershutdown.id = TSK_INVALID_TIMER_ID; self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; return 0; }
/* Started -> (SUBSCRIBE) -> Trying */ int tsip_dialog_subscribe_Started_2_Trying_X_subscribe(va_list *app) { tsip_dialog_subscribe_t *self; self = va_arg(*app, tsip_dialog_subscribe_t *); TSIP_DIALOG(self)->running = tsk_true; /* alert the user */ TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); return send_SUBSCRIBE(self); }
// Current -> (oINVITE) -> Current static int x0500_Current_2_Current_X_oINVITE(va_list *app) { int ret; tsip_dialog_invite_t *self; const tsip_action_t* action; const tsip_message_t *message; tmedia_type_t media_type; static const tsk_bool_t __force_restart_is_yes = tsk_true; self = va_arg(*app, tsip_dialog_invite_t *); message = va_arg(*app, const tsip_message_t *); action = va_arg(*app, const tsip_action_t *); media_type = (action && action->media.type != tmedia_none) ? action->media.type : TSIP_DIALOG_GET_SS(self)->media.type; self->is_client = tsk_true; tsip_dialog_invite_ice_save_action(self, _fsm_action_oINVITE, action, message); // Cancel without notifying ("silent mode") and perform the operation right now ("sync mode") tsip_dialog_invite_ice_cancel_silent_and_sync_ctx(self); // create ICE context if((ret = tsip_dialog_invite_ice_create_ctx(self, media_type))){ TSK_DEBUG_ERROR("tsip_dialog_invite_ice_create_ctx() failed"); return ret; } // For now disable ICE timers until we receive the 2xx ret = tsip_dialog_invite_ice_timers_set(self, -1); // Start ICE ret = tsip_dialog_invite_ice_start_ctx(self); // alert the user only if we are in initial state which means that it's not media update if(TSIP_DIALOG(self)->state == tsip_initial){ TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); } return ret; }
/** * @fn int tsip_dialog_register_event_callback(const tsip_dialog_register_t *self, tsip_dialog_event_type_t type, * const tsip_message_t *msg) * * @brief Callback function called to alert the dialog for new events from the transaction/transport layers. * * @param [in,out] self A reference to the dialog. * @param type The event type. * @param [in,out] msg The incoming SIP/IMS message. * * @return Zero if succeed and non-zero error code otherwise. **/ int tsip_dialog_register_event_callback(const tsip_dialog_register_t *self, tsip_dialog_event_type_t type, const tsip_message_t *msg) { int ret = -1; switch(type){ case tsip_dialog_i_msg: { if(msg){ if(TSIP_MESSAGE_IS_RESPONSE(msg)){ // // RESPONSE // const tsip_action_t* action = tsip_dialog_keep_action(TSIP_DIALOG(self), msg) ? TSIP_DIALOG(self)->curr_action : tsk_null; if(TSIP_RESPONSE_IS_1XX(msg)){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_1xx, msg, action); } else if(TSIP_RESPONSE_IS_2XX(msg)){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_2xx, msg, action); } else if(TSIP_RESPONSE_IS(msg,401) || TSIP_RESPONSE_IS(msg,407) || TSIP_RESPONSE_IS(msg,421) || TSIP_RESPONSE_IS(msg,494)){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); } else if(TSIP_RESPONSE_IS(msg,423)){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_423, msg, action); } else{ // Alert User ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); /* TSK_DEBUG_WARN("Not supported status code: %d", TSIP_RESPONSE_CODE(msg)); */ } } else{ // // REQUEST // if(TSIP_REQUEST_IS_REGISTER(msg)){ ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iREGISTER, msg, tsk_null); } } } break; } case tsip_dialog_canceled: { ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_cancel, msg, tsk_null); break; } case tsip_dialog_terminated: case tsip_dialog_timedout: case tsip_dialog_error: case tsip_dialog_transport_error: { ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); break; } default: break; } return ret; }
static tsk_bool_t _fsm_cond_not_silent_hangup(tsip_dialog_register_t* dialog, tsip_message_t* message) { return !TSIP_DIALOG(dialog)->ss->silent_hangup; }
/** Initializes the dialog. * * @param [in,out] self The dialog to initialize. **/ int tsip_dialog_subscribe_init(tsip_dialog_subscribe_t *self) { /* Initialize the State Machine. */ tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), /*======================= * === Started === */ // Started -> (Send) -> Trying TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_subscribe, _fsm_state_Trying, tsip_dialog_subscribe_Started_2_Trying_X_subscribe, "tsip_dialog_subscribe_Started_2_Trying_X_subscribe"), // Started -> (Any) -> Started TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_subscribe_Started_2_Started_X_any"), /*======================= * === Trying === */ // Trying -> (1xx) -> Trying TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_1xx, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_1xx, "tsip_dialog_subscribe_Trying_2_Trying_X_1xx"), // Trying -> (2xx) -> Terminated TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_unsubscribing, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_2xx, "tsip_dialog_subscribe_Trying_2_Terminated_X_2xx"), // Trying -> (2xx) -> Connected TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_subscribing, _fsm_state_Connected, tsip_dialog_subscribe_Trying_2_Connected_X_2xx, "tsip_dialog_subscribe_Trying_2_Connected_X_2xx"), // Trying -> (401/407/421/494) -> Trying TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_401_407_421_494, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_401_407_421_494, "tsip_dialog_subscribe_Trying_2_Trying_X_401_407_421_494"), // Trying -> (423) -> Trying TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_423, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_423, "tsip_dialog_subscribe_Trying_2_Trying_X_423"), // Trying -> (300_to_699) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_300_to_699, "tsip_dialog_subscribe_Trying_2_Terminated_X_300_to_699"), // Trying -> (cancel) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_cancel, "tsip_dialog_subscribe_Trying_2_Terminated_X_cancel"), // Trying -> (Notify) -> Trying TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_notify, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_NOTIFY, "tsip_dialog_subscribe_Trying_2_Trying_X_NOTIFY"), // Trying -> (hangup) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Trying_2_Terminated_X_hangup"), // Trying -> (shutdown) -> Terminated TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Trying_2_Terminated_X_shutdown"), // Trying -> (Any) -> Trying //TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Trying, "tsip_dialog_subscribe_Trying_2_Trying_X_any"), /*======================= * === Connected === */ // Connected -> (SUBSCRIBE) -> Trying TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_subscribe, _fsm_state_Trying, tsip_dialog_subscribe_Connected_2_Trying_X_subscribe, "tsip_dialog_subscribe_Connected_2_Trying_X_subscribe"), // Connected -> (NOTIFY) -> Connected TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_notify, _fsm_cond_notify_not_terminated, _fsm_state_Connected, tsip_dialog_subscribe_Connected_2_Connected_X_NOTIFY, "tsip_dialog_subscribe_Connected_2_Connected_X_NOTIFY"), // Connected -> (NOTIFY) -> Terminated TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_notify, _fsm_cond_notify_terminated, _fsm_state_Terminated, tsip_dialog_subscribe_Connected_2_Terminated_X_NOTIFY, "tsip_dialog_subscribe_Connected_2_Terminated_X_NOTIFY"), /*======================= * === Any === */ // Any -> (hangup) -> Trying TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_not_silent_hangup, _fsm_state_Trying, tsip_dialog_subscribe_Any_2_Trying_X_hangup, "tsip_dialog_subscribe_Any_2_Trying_X_hangup"), // Any -> (silenthangup) -> Terminated TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_silent_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Any_2_Trying_X_silenthangup"), // Any -> (shutdown) -> Trying TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_not_silent_shutdown, _fsm_state_Trying, tsip_dialog_subscribe_Any_2_Trying_X_shutdown, "tsip_dialog_subscribe_Any_2_Trying_X_shutdown"), // Any -> (silentshutdown) -> Terminated TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_silent_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Any_2_Trying_X_silentshutdown"), // Any -> (shutdown timedout) -> Terminated TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_shutdown_timedout"), // Any -> (transport error) -> Terminated TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_subscribe_Any_2_Terminated_X_transportError, "tsip_dialog_subscribe_Any_2_Terminated_X_transportError"), // Any -> (error) -> Terminated TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_subscribe_Any_2_Terminated_X_Error, "tsip_dialog_subscribe_Any_2_Terminated_X_Error"), TSK_FSM_ADD_NULL()); /* Sets callback function */ TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_subscribe_event_callback); /* Timers */ self->timerrefresh.id = TSK_INVALID_TIMER_ID; self->timerrefresh.timeout = TSIP_DIALOG(self)->expires; self->timershutdown.id = TSK_INVALID_TIMER_ID; self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; return 0; }
static tsk_bool_t _fsm_cond_silent_hangup(tsip_dialog_subscribe_t* dialog, tsip_message_t* message) { return TSIP_DIALOG(dialog)->ss->silent_hangup; }