diff options
author | oej <oej@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-12-05 17:29:43 +0000 |
---|---|---|
committer | oej <oej@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-12-05 17:29:43 +0000 |
commit | cb4982e5713f6f5893ac284a1a2bb0bd8ed17b94 (patch) | |
tree | 187e09dee383a061b171040d69ac39dbb73dff7b /channels | |
parent | 8ba0ef188eedae4b7aa98642811a0f2feff8dabd (diff) |
Merging the invitestate-1.4 branch after successful testing.
Will check if I can solve this with less changes in 1.2.
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@48270 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 96 |
1 files changed, 75 insertions, 21 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index eb381a7e2..ccf3911ea 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -244,6 +244,21 @@ enum sip_result { AST_FAILURE = -1, }; +/*! \brief States for the INVITE transaction, not the dialog + \note this is for the INVITE that sets up the dialog +*/ +enum invitestates { + INV_NONE = 0, /*!< No state at all, maybe not an INVITE dialog */ + INV_CALLING = 1, /*!< Invite sent, no answer */ + INV_PROCEEDING = 2, /*!< We got/sent 1xx message */ + INV_EARLY_MEDIA = 3, /*!< We got 18x message with to-tag back */ + INV_COMPLETED = 4, /*!< Got final response with error. Wait for ACK, then CONFIRMED */ + INV_CONFIRMED = 5, /*!< Confirmed response - we've got an ack (Incoming calls only) */ + INV_TERMINATED = 6, /*!< Transaction done - either successful (AST_STATE_UP) or failed, but done + The only way out of this is a BYE from one side */ + INV_CANCELLED = 7, /*!< Transaction cancelled by client or server in non-terminated state */ +}; + /* Do _NOT_ make any changes to this enum, or the array following it; if you think you are doing the right thing, you are probably not doing the right thing. If you think there are changes @@ -703,7 +718,7 @@ struct sip_auth { #define SIP_REALTIME (1 << 11) /*!< Flag for realtime users */ #define SIP_USECLIENTCODE (1 << 12) /*!< Trust X-ClientCode info message */ #define SIP_OUTGOING (1 << 13) /*!< Direction of the last transaction in this dialog */ -#define SIP_CAN_BYE (1 << 14) /*!< Can we send BYE on this dialog? */ +#define SIP_FREE_BIT (1 << 14) /*!< ---- */ #define SIP_DEFER_BYE_ON_TRANSFER (1 << 15) /*!< Do not hangup at first ast_hangup */ #define SIP_DTMF (3 << 16) /*!< DTMF Support: four settings, uses two bits */ #define SIP_DTMF_RFC2833 (0 << 16) /*!< DTMF Support: RTP DTMF - "rfc2833" */ @@ -877,6 +892,7 @@ struct sip_refer { static struct sip_pvt { ast_mutex_t lock; /*!< Dialog private lock */ int method; /*!< SIP method that opened this dialog */ + enum invitestates invitestate; /*!< The state of the INVITE transaction only */ AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(callid); /*!< Global CallID */ AST_STRING_FIELD(randdata); /*!< Random data */ @@ -1593,6 +1609,13 @@ static void initialize_initreq(struct sip_pvt *p, struct sip_request *req) ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines); } +static void sip_alreadygone(struct sip_pvt *dialog) +{ + if (option_debug > 2) + ast_log(LOG_DEBUG, "Setting SIP_ALREADYGONE on dialog %s\n", dialog->callid); + ast_set_flag(&dialog->flags[0], SIP_ALREADYGONE); +} + /*! \brief returns true if 'name' (with optional trailing whitespace) * matches the sip method 'id'. @@ -1871,7 +1894,7 @@ static int retrans_pkt(void *data) ast_mutex_lock(&pkt->owner->lock); } if (pkt->owner->owner) { - ast_set_flag(&pkt->owner->flags[0], SIP_ALREADYGONE); + sip_alreadygone(pkt->owner); ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet.\n", pkt->owner->callid); ast_queue_hangup(pkt->owner->owner); ast_channel_unlock(pkt->owner->owner); @@ -2802,6 +2825,7 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout) if (option_debug > 1) ast_log(LOG_DEBUG,"Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability); transmit_invite(p, SIP_INVITE, 1, 2); + p->invitestate = INV_CALLING; /* Initialize auto-congest time */ p->initid = ast_sched_add(sched, p->maxtime ? (p->maxtime * 4) : SIP_TRANS_TIMEOUT, auto_congest, p); @@ -3269,7 +3293,7 @@ static int sip_hangup(struct ast_channel *ast) return 0; } /* If the call is not UP, we need to send CANCEL instead of BYE */ - if (ast->_state == AST_STATE_RING || ast->_state == AST_STATE_RINGING) { + if (ast->_state == AST_STATE_RING || ast->_state == AST_STATE_RINGING || p->invitestate < INV_COMPLETED) { needcancel = TRUE; if (option_debug > 3) ast_log(LOG_DEBUG, "Hanging up channel in state %s (not UP)\n", ast_state2str(ast->_state)); @@ -3293,7 +3317,7 @@ static int sip_hangup(struct ast_channel *ast) */ if (ast_test_flag(&p->flags[0], SIP_ALREADYGONE)) needdestroy = 1; /* Set destroy flag at end of this function */ - else + else if (p->invitestate != INV_CALLING) sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); /* Start the process if it's not already started */ @@ -3304,7 +3328,8 @@ static int sip_hangup(struct ast_channel *ast) __sip_pretend_ack(p); /* if we can't send right now, mark it pending */ - if (!ast_test_flag(&p->flags[0], SIP_CAN_BYE)) { + if (p->invitestate == INV_CALLING) { + /* We can't send anything in CALLING state */ ast_set_flag(&p->flags[0], SIP_PENDINGBYE); /* Do we need a timer here if we don't hear from them at all? */ } else { @@ -3354,6 +3379,7 @@ static int sip_hangup(struct ast_channel *ast) but we can't send one while we have "INVITE" outstanding. */ ast_set_flag(&p->flags[0], SIP_PENDINGBYE); ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE); + sip_cancel_destroy(p); } } } @@ -3608,6 +3634,7 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data switch(condition) { case AST_CONTROL_RINGING: if (ast->_state == AST_STATE_RING) { + p->invitestate = INV_EARLY_MEDIA; if (!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) || (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) { /* Send 180 ringing if out-of-band seems reasonable */ @@ -3624,7 +3651,8 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data case AST_CONTROL_BUSY: if (ast->_state != AST_STATE_UP) { transmit_response(p, "486 Busy Here", &p->initreq); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + p->invitestate = INV_TERMINATED; + sip_alreadygone(p); ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV); break; } @@ -3633,7 +3661,8 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data case AST_CONTROL_CONGESTION: if (ast->_state != AST_STATE_UP) { transmit_response(p, "503 Service Unavailable", &p->initreq); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + p->invitestate = INV_TERMINATED; + sip_alreadygone(p); ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV); break; } @@ -3644,6 +3673,7 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { transmit_response(p, "100 Trying", &p->initreq); + p->invitestate = INV_PROCEEDING; break; } res = -1; @@ -3652,6 +3682,7 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data if ((ast->_state != AST_STATE_UP) && !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { + p->invitestate = INV_EARLY_MEDIA; transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE); ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); break; @@ -7374,6 +7405,9 @@ static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, enum xm { struct sip_request resp; + if (sipmethod == SIP_ACK) + p->invitestate = INV_CONFIRMED; + reqprep(&resp, p, sipmethod, seqno, newbranch); add_header_contentLength(&resp, 0); return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq); @@ -11462,7 +11496,7 @@ static void check_pendings(struct sip_pvt *p) { if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) { /* if we can't BYE, then this is really a pending CANCEL */ - if (!ast_test_flag(&p->flags[0], SIP_CAN_BYE)) + if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA) transmit_request(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, FALSE); /* Actually don't destroy us yet, wait for the 487 on our original INVITE, but do set an autodestruct just in case we never get it. */ @@ -11513,6 +11547,15 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 183) resp = 183; + /* Any response between 100 and 199 is PROCEEDING */ + if (resp >= 100 && resp < 200 && p->invitestate == INV_CALLING) + p->invitestate = INV_PROCEEDING; + + /* Final response, not 200 ? */ + if (resp >= 300 && (p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA )) + p->invitestate = INV_COMPLETED; + + switch (resp) { case 100: /* Trying */ case 101: /* Dialog establishment */ @@ -11531,13 +11574,13 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru } } if (find_sdp(req)) { + p->invitestate = INV_EARLY_MEDIA; res = process_sdp(p, req); if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) { /* Queue a progress frame only if we have SDP in 180 */ ast_queue_control(p->owner, AST_CONTROL_PROGRESS); } } - ast_set_flag(&p->flags[0], SIP_CAN_BYE); check_pendings(p); break; @@ -11546,13 +11589,13 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru sip_cancel_destroy(p); /* Ignore 183 Session progress without SDP */ if (find_sdp(req)) { + p->invitestate = INV_EARLY_MEDIA; res = process_sdp(p, req); if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) { /* Queue a progress frame */ ast_queue_control(p->owner, AST_CONTROL_PROGRESS); } } - ast_set_flag(&p->flags[0], SIP_CAN_BYE); check_pendings(p); break; @@ -11653,8 +11696,8 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru ast_set_flag(&p->flags[0], SIP_PENDINGBYE); } /* If I understand this right, the branch is different for a non-200 ACK only */ + p->invitestate = INV_TERMINATED; transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, TRUE); - ast_set_flag(&p->flags[0], SIP_CAN_BYE); check_pendings(p); break; case 407: /* Proxy authentication */ @@ -11672,7 +11715,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, authenticate, authorization, SIP_INVITE, 1)) { ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From")); ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + sip_alreadygone(p); if (p->owner) ast_queue_control(p->owner, AST_CONTROL_CONGESTION); } @@ -11686,14 +11729,14 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) ast_queue_control(p->owner, AST_CONTROL_CONGESTION); ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + sip_alreadygone(p); break; case 404: /* Not found */ transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE)) ast_queue_control(p->owner, AST_CONTROL_CONGESTION); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + sip_alreadygone(p); break; case 481: /* Call leg does not exist */ @@ -12150,7 +12193,6 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_ /* Fatal response */ if ((option_verbose > 2) && (resp != 487)) ast_verbose(VERBOSE_PREFIX_3 "Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(p->sa.sin_addr)); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */ @@ -12209,7 +12251,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_ /* ACK on invite */ if (sipmethod == SIP_INVITE) transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + sip_alreadygone(p); if (!p->owner) ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); } else if ((resp >= 100) && (resp < 200)) { @@ -13254,6 +13296,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int if (option_debug > 1) ast_log(LOG_DEBUG, "%s: New call is still down.... Trying... \n", c->name); transmit_response(p, "100 Trying", req); + p->invitestate = INV_PROCEEDING; ast_setstate(c, AST_STATE_RING); if (strcmp(p->exten, ast_pickup_ext())) { /* Call to extension -start pbx on this call */ enum ast_pbx_result res; @@ -13263,6 +13306,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int switch(res) { case AST_PBX_FAILED: ast_log(LOG_WARNING, "Failed to start PBX :(\n"); + p->invitestate = INV_COMPLETED; if (ast_test_flag(req, SIP_PKT_IGNORE)) transmit_response(p, "503 Unavailable", req); else @@ -13270,6 +13314,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int break; case AST_PBX_CALL_LIMIT: ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n"); + p->invitestate = INV_COMPLETED; if (ast_test_flag(req, SIP_PKT_IGNORE)) transmit_response(p, "480 Temporarily Unavailable", req); else @@ -13297,7 +13342,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int transmit_response(p, "503 Unavailable", req); /* OEJ - Right answer? */ else transmit_response_reliable(p, "503 Unavailable", req); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + sip_alreadygone(p); /* Unlock locks so ast_hangup can do its magic */ ast_mutex_unlock(&p->lock); c->hangupcause = AST_CAUSE_CALL_REJECTED; @@ -13306,6 +13351,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int ast_setstate(c, AST_STATE_DOWN); c->hangupcause = AST_CAUSE_NORMAL_CLEARING; } + p->invitestate = INV_COMPLETED; ast_hangup(c); ast_mutex_lock(&p->lock); c = NULL; @@ -13313,9 +13359,11 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int break; case AST_STATE_RING: transmit_response(p, "100 Trying", req); + p->invitestate = INV_PROCEEDING; break; case AST_STATE_RINGING: transmit_response(p, "180 Ringing", req); + p->invitestate = INV_PROCEEDING; break; case AST_STATE_UP: if (option_debug > 1) @@ -13401,6 +13449,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int transmit_response_with_sdp(p, "200 OK", req, XMIT_CRITICAL); } + p->invitestate = INV_TERMINATED; break; default: ast_log(LOG_WARNING, "Don't know how to handle INVITE in state %d\n", c->_state); @@ -13421,6 +13470,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int transmit_response(p, msg, req); else transmit_response_reliable(p, msg, req); + p->invitestate = INV_COMPLETED; sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); } } @@ -13616,7 +13666,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int transmit_response(p, "603 Declined (No dialog)", req); if (!ast_test_flag(req, SIP_PKT_IGNORE)) { append_history(p, "Xfer", "Refer failed. Outside of dialog."); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + sip_alreadygone(p); ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); } return 0; @@ -13875,7 +13925,8 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req) { check_via(p, req); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + sip_alreadygone(p); + p->invitestate = INV_CANCELLED; if (p->owner && p->owner->_state == AST_STATE_UP) { /* This call is up, cancel is ignored, we need a bye */ @@ -13908,12 +13959,14 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req) struct ast_channel *bridged_to; /* If we have an INCOMING invite that we haven't answered, terminate that transaction */ - if (p->pendinginvite && !ast_test_flag(&p->flags[0], SIP_OUTGOING) && !ast_test_flag(req, SIP_PKT_IGNORE) && !p->owner) + if (p->pendinginvite && !ast_test_flag(&p->flags[0], SIP_OUTGOING) && !ast_test_flag(req, SIP_PKT_IGNORE) && !p->owner) transmit_response_reliable(p, "487 Request Terminated", &p->initreq); + p->invitestate = INV_TERMINATED; + copy_request(&p->initreq, req); check_via(p, req); - ast_set_flag(&p->flags[0], SIP_ALREADYGONE); + sip_alreadygone(p); /* Get RTCP quality before end of call */ if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY) || p->owner) { @@ -14479,6 +14532,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc case SIP_ACK: /* Make sure we don't ignore this */ if (seqno == p->pendinginvite) { + p->invitestate = INV_CONFIRMED; p->pendinginvite = 0; __sip_ack(p, seqno, FLAG_RESPONSE, 0); if (find_sdp(req)) { |