📄 sip_xaction_state_mc.c
字号:
/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END *//* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */#pragma ident "@(#)sip_xaction_state_mc.c 1.13 06/08/16 SMI"/* * SIP Client/Server Invite/Non-Invite Transaction State machine. */#include "sip_xaction.h"#include "sip_msg.h"#include "sip_miscdefs.h"/* * Some Timer related info from RFC 3261, page 265. * * ---------------------------------------------------------------------- * Timer Value Section Meaning * ---------------------------------------------------------------------- * T1 500ms default Section 17.1.1.1 RTT Estimate * T2 4s Section 17.1.2.2 The maximum retransmit * interval for non-INVITE * requests and INVITE * responses * T4 5s Section 17.1.2.2 Maximum duration a * message will * remain in the network * ---------------------------------------------------------------------- * Timer A initially T1 Section 17.1.1.2 INVITE request retransmit * interval, for UDP only * Timer B 64*T1 Section 17.1.1.2 INVITE transaction * timeout timer * Timer C > 3min Section 16.6 proxy INVITE transaction * bullet 11 timeout * Timer D > 32s for UDP Section 17.1.1.2 Wait time for response * 0s for TCP/SCTP retransmits * Timer E initially T1 Section 17.1.2.2 non-INVITE request * retransmit interval, * UDP only * Timer F 64*T1 Section 17.1.2.2 non-INVITE transaction * timeout timer * Timer G initially T1 Section 17.2.1 INVITE response * retransmit interval * Timer H 64*T1 Section 17.2.1 Wait time for * ACK receipt * Timer I T4 for UDP Section 17.2.1 Wait time for * 0s for TCP/SCTP ACK retransmits * Timer J 64*T1 for UDP Section 17.2.2 Wait time for * 0s for TCP/SCTP non-INVITE request * retransmits * Timer K T4 for UDP Section 17.1.2.2 Wait time for * 0s for TCP/SCTP response retransmits * ---------------------------------------------------------------------- */#ifndef MIN#define MIN(a, b) (((a) < (b)) ? (a):(b))#endif/* Arg to the timer fire routine */typedef struct sip_xaction_timer_obj_s { sip_xaction_timer_type_t sip_xaction_timer_type; sip_xaction_t *sip_trans; int sip_xaction_timer_xport;} sip_xaction_time_obj_t;int sip_xaction_output(sip_conn_object_t, sip_xaction_t *, _sip_msg_t *);int sip_xaction_input(sip_conn_object_t, sip_xaction_t *, _sip_msg_t **);void sip_xaction_terminate(sip_xaction_t *, _sip_msg_t *, int);static int sip_clnt_xaction_output(sip_conn_object_t, sip_xaction_t *, _sip_msg_t *);static int sip_clnt_xaction_input(sip_conn_object_t, sip_xaction_t *, _sip_msg_t **);static int sip_clnt_xaction_inv_res(sip_conn_object_t, sip_xaction_t *, _sip_msg_t **);static int sip_clnt_xaction_noninv_res(sip_conn_object_t, sip_xaction_t *, _sip_msg_t **);static int sip_srv_xaction_output(sip_conn_object_t, sip_xaction_t *, _sip_msg_t *);static int sip_srv_xaction_input(sip_conn_object_t, sip_xaction_t *, _sip_msg_t **);static int sip_srv_xaction_inv_res(sip_conn_object_t, sip_xaction_t *, _sip_msg_t *);static int sip_srv_xaction_noninv_res(sip_conn_object_t, sip_xaction_t *, _sip_msg_t *);static int sip_create_send_nonOKack(sip_conn_object_t, sip_xaction_t *, _sip_msg_t *, boolean_t);void sip_xaction_state_timer_fire(void *);static sip_xaction_time_obj_t *sip_setup_timer(sip_conn_object_t, sip_xaction_t *, _sip_msg_t *, sip_timer_t, int);/* Return a timer object */static sip_xaction_time_obj_t *sip_setup_timer(sip_conn_object_t conn_obj, sip_xaction_t *sip_trans, _sip_msg_t *sip_msg, sip_timer_t timer, int type){ sip_xaction_time_obj_t *sip_timer_obj = NULL; sip_timer_obj = (sip_xaction_time_obj_t *) malloc(sizeof (sip_xaction_time_obj_t)); if (sip_timer_obj == NULL) return (NULL); if (SIP_IS_TIMER_RUNNING(timer)) SIP_CANCEL_TIMER(timer); sip_timer_obj->sip_xaction_timer_type = type; sip_timer_obj->sip_xaction_timer_xport = sip_conn_transport(conn_obj); sip_timer_obj->sip_trans = sip_trans; /* Save the message */ if (sip_msg != NULL) { (void) sip_add_conn_obj_cache(conn_obj, (void *)sip_trans); if (sip_trans->sip_xaction_last_msg != NULL) { SIP_MSG_REFCNT_DECR(sip_trans->sip_xaction_last_msg); sip_trans->sip_xaction_last_msg = NULL; } SIP_MSG_REFCNT_INCR(sip_msg); sip_trans->sip_xaction_last_msg = sip_msg; } return (sip_timer_obj);}/* * --------------------------- Output Routines --------------------------- *//* Send a SIP message, request or response, out */intsip_xaction_output(sip_conn_object_t conn_obj, sip_xaction_t *sip_trans, _sip_msg_t *msg){ sip_message_type_t *sip_msg_info; int ret; assert(conn_obj != NULL); sip_msg_info = msg->sip_msg_req_res; if (sip_msg_info->is_request) return (sip_clnt_xaction_output(conn_obj, sip_trans, msg)); ret = sip_srv_xaction_output(conn_obj, sip_trans, msg); return (ret);}/* Send a Request out */static intsip_clnt_xaction_output(sip_conn_object_t conn_obj, sip_xaction_t *sip_trans, _sip_msg_t *msg){ sip_xaction_time_obj_t *timer_obj_A = NULL; sip_xaction_time_obj_t *timer_obj_B = NULL; sip_xaction_time_obj_t *timer_obj_E = NULL; sip_xaction_time_obj_t *timer_obj_F = NULL; sip_message_type_t *sip_msg_info; int prev_state; int error = 0; boolean_t isreliable; (void) pthread_mutex_lock(&sip_trans->sip_xaction_mutex); prev_state = sip_trans->sip_xaction_state; assert(msg->sip_msg_req_res != NULL); sip_msg_info = msg->sip_msg_req_res; isreliable = sip_is_conn_reliable(conn_obj); if (sip_msg_info->sip_req_method == INVITE) { /* * if transport is not reliable, start TIMER A. */ if (!isreliable) { timer_obj_A = sip_setup_timer(conn_obj, sip_trans, msg, sip_trans->sip_xaction_TA, SIP_XACTION_TIMER_A); if (timer_obj_A == NULL) { error = ENOMEM; goto error_ret; } } timer_obj_B = sip_setup_timer(conn_obj, sip_trans, NULL, sip_trans->sip_xaction_TB, SIP_XACTION_TIMER_B); if (timer_obj_B == NULL) { error = ENOMEM; goto error_ret; } if (timer_obj_A != NULL) { SIP_SCHED_TIMER(sip_trans->sip_xaction_TA, timer_obj_A, sip_xaction_state_timer_fire); if (!SIP_IS_TIMER_RUNNING(sip_trans->sip_xaction_TA)) { error = ENOMEM; goto error_ret; } } SIP_SCHED_TIMER(sip_trans->sip_xaction_TB, timer_obj_B, sip_xaction_state_timer_fire); if (!SIP_IS_TIMER_RUNNING(sip_trans->sip_xaction_TB)) { if (timer_obj_A != NULL) SIP_CANCEL_TIMER(sip_trans->sip_xaction_TA) error = ENOMEM; goto error_ret; } sip_trans->sip_xaction_state = SIPS_CLNT_CALLING; } else { /* * if transport is not reliable, start rexmit Timer E. */ if (!isreliable) { timer_obj_E = sip_setup_timer(conn_obj, sip_trans, msg, sip_trans->sip_xaction_TE, SIP_XACTION_TIMER_E); if (timer_obj_E == NULL) { error = ENOMEM; goto error_ret; } } /* Start transaction Timer F */ timer_obj_F = sip_setup_timer(conn_obj, sip_trans, NULL, sip_trans->sip_xaction_TF, SIP_XACTION_TIMER_F); if (timer_obj_F == NULL) { error = ENOMEM; goto error_ret; } if (timer_obj_E != NULL) { SIP_SCHED_TIMER(sip_trans->sip_xaction_TE, timer_obj_E, sip_xaction_state_timer_fire); if (!SIP_IS_TIMER_RUNNING(sip_trans->sip_xaction_TE)) { error = ENOMEM; goto error_ret; } } SIP_SCHED_TIMER(sip_trans->sip_xaction_TF, timer_obj_F, sip_xaction_state_timer_fire); if (!SIP_IS_TIMER_RUNNING(sip_trans->sip_xaction_TF)) { if (timer_obj_E != NULL) SIP_CANCEL_TIMER(sip_trans->sip_xaction_TE) error = ENOMEM; goto error_ret; } sip_trans->sip_xaction_state = SIPS_CLNT_TRYING; } (void) pthread_mutex_unlock(&sip_trans->sip_xaction_mutex); if (sip_xaction_ulp_state_cb != NULL) { sip_xaction_ulp_state_cb((sip_transaction_t)sip_trans, (sip_msg_t)msg, prev_state, sip_trans->sip_xaction_state); } return (0);error_ret: (void) pthread_mutex_unlock(&sip_trans->sip_xaction_mutex); if (timer_obj_A != NULL) free(timer_obj_A); if (timer_obj_B != NULL) free(timer_obj_B); if (timer_obj_E != NULL) free(timer_obj_E); if (timer_obj_F != NULL) free(timer_obj_F); return (error);}/* Send a response out */static intsip_srv_xaction_output(sip_conn_object_t conn_obj, sip_xaction_t *sip_trans, _sip_msg_t *msg){ int ret; if (sip_trans->sip_xaction_method == INVITE) ret = sip_srv_xaction_inv_res(conn_obj, sip_trans, msg); else ret = sip_srv_xaction_noninv_res(conn_obj, sip_trans, msg); return (ret);}/* Send a INVITE response out */static intsip_srv_xaction_inv_res(sip_conn_object_t conn_obj, sip_xaction_t *sip_trans, _sip_msg_t *msg){ int resp_code; sip_xaction_time_obj_t *timer_obj_G = NULL; sip_xaction_time_obj_t *timer_obj_H = NULL; sip_message_type_t *sip_msg_info = msg->sip_msg_req_res; int prev_state; boolean_t isreliable; isreliable = sip_is_conn_reliable(conn_obj); resp_code = sip_msg_info->sip_resp_code; (void) pthread_mutex_lock(&sip_trans->sip_xaction_mutex); prev_state = sip_trans->sip_xaction_state; switch (sip_trans->sip_xaction_state) { case SIPS_SRV_INV_PROCEEDING: if (SIP_PROVISIONAL_RESP(resp_code)) { if (sip_trans->sip_xaction_last_msg != NULL) { SIP_MSG_REFCNT_DECR( sip_trans->sip_xaction_last_msg); sip_trans->sip_xaction_last_msg = NULL; } SIP_MSG_REFCNT_INCR(msg); sip_trans->sip_xaction_last_msg = msg; (void) sip_add_conn_obj_cache(conn_obj, (void *)sip_trans); } else if (SIP_OK_RESP(resp_code)) { sip_trans->sip_xaction_state = SIPS_SRV_INV_TERMINATED; } else if (SIP_NONOK_FINAL_RESP(resp_code)) { if (sip_trans->sip_xaction_last_msg != NULL) { SIP_MSG_REFCNT_DECR( sip_trans->sip_xaction_last_msg); sip_trans->sip_xaction_last_msg = NULL; } SIP_MSG_REFCNT_INCR(msg); sip_trans->sip_xaction_last_msg = msg; (void) sip_add_conn_obj_cache(conn_obj, (void *)sip_trans); /* For unreliable transport start timer G */ if (!isreliable) { timer_obj_G = sip_setup_timer( conn_obj, sip_trans, NULL, sip_trans->sip_xaction_TG, SIP_XACTION_TIMER_G); if (timer_obj_G == NULL) { (void) pthread_mutex_unlock( &sip_trans-> sip_xaction_mutex); return (ENOMEM); } } /* Start Timer H */ timer_obj_H = sip_setup_timer( conn_obj, sip_trans, NULL, sip_trans->sip_xaction_TH, SIP_XACTION_TIMER_H); if (timer_obj_H == NULL) { if (timer_obj_G != NULL) free(timer_obj_G); (void) pthread_mutex_unlock( &sip_trans->sip_xaction_mutex); return (ENOMEM); } if (timer_obj_G != NULL) { SIP_SCHED_TIMER( sip_trans->sip_xaction_TG, timer_obj_G, sip_xaction_state_timer_fire); if (!SIP_IS_TIMER_RUNNING( sip_trans->sip_xaction_TG)) { (void) pthread_mutex_unlock( &sip_trans-> sip_xaction_mutex); free(timer_obj_G); return (ENOMEM); } } if (timer_obj_H != NULL) { SIP_SCHED_TIMER( sip_trans->sip_xaction_TH, timer_obj_H, sip_xaction_state_timer_fire); if (!SIP_IS_TIMER_RUNNING( sip_trans->sip_xaction_TH)) { if (timer_obj_G != NULL) { SIP_CANCEL_TIMER( sip_trans-> sip_xaction_TG); free(timer_obj_G); } (void) pthread_mutex_unlock( &sip_trans-> sip_xaction_mutex); free(timer_obj_H); return (ENOMEM); } } sip_trans->sip_xaction_state = SIPS_SRV_INV_COMPLETED; } break; default: (void) pthread_mutex_unlock( &sip_trans->sip_xaction_mutex); return (EPROTO); } (void) pthread_mutex_unlock(&sip_trans->sip_xaction_mutex); if (prev_state != sip_trans->sip_xaction_state && sip_xaction_ulp_state_cb != NULL) { sip_xaction_ulp_state_cb((sip_transaction_t)sip_trans, (sip_msg_t)msg, prev_state, sip_trans->sip_xaction_state); } return (0);}/* Send a NON-INVITE response out */static intsip_srv_xaction_noninv_res(sip_conn_object_t conn_obj, sip_xaction_t *sip_trans, _sip_msg_t *msg){ int resp_code; sip_xaction_time_obj_t *timer_obj_J = NULL; sip_message_type_t *sip_msg_info = msg->sip_msg_req_res; int prev_state; boolean_t isreliable; resp_code = sip_msg_info->sip_resp_code; isreliable = sip_is_conn_reliable(conn_obj); (void) pthread_mutex_lock(&sip_trans->sip_xaction_mutex); prev_state = sip_trans->sip_xaction_state; switch (sip_trans->sip_xaction_state) { case SIPS_SRV_TRYING: if (sip_trans->sip_xaction_last_msg != NULL) { SIP_MSG_REFCNT_DECR( sip_trans->sip_xaction_last_msg); sip_trans->sip_xaction_last_msg = NULL; } SIP_MSG_REFCNT_INCR(msg); sip_trans->sip_xaction_last_msg = msg; (void) sip_add_conn_obj_cache(conn_obj, (void *)sip_trans); if (SIP_PROVISIONAL_RESP(resp_code)) { sip_trans->sip_xaction_state = SIPS_SRV_NONINV_PROCEEDING; } else if (SIP_FINAL_RESP(resp_code)) { /* For unreliable transports, start Timer J */ if (!isreliable) { timer_obj_J = sip_setup_timer( conn_obj, sip_trans, NULL, sip_trans->sip_xaction_TJ, SIP_XACTION_TIMER_J); if (timer_obj_J == NULL) { (void) pthread_mutex_unlock(& sip_trans-> sip_xaction_mutex); return (ENOMEM); } SIP_SCHED_TIMER( sip_trans->sip_xaction_TJ, timer_obj_J, sip_xaction_state_timer_fire); if (!SIP_IS_TIMER_RUNNING( sip_trans->sip_xaction_TJ)) { (void) pthread_mutex_unlock(& sip_trans-> sip_xaction_mutex); free(timer_obj_J); return (ENOMEM); } sip_trans->sip_xaction_state = SIPS_SRV_NONINV_COMPLETED; } else { sip_trans->sip_xaction_state = SIPS_SRV_NONINV_TERMINATED; } } break; case SIPS_SRV_NONINV_PROCEEDING: if (sip_trans->sip_xaction_last_msg != NULL) { SIP_MSG_REFCNT_DECR( sip_trans->sip_xaction_last_msg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -