]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merging the invitestate-1.4 branch after successful testing.
authorOlle Johansson <oej@edvina.net>
Tue, 5 Dec 2006 17:29:43 +0000 (17:29 +0000)
committerOlle Johansson <oej@edvina.net>
Tue, 5 Dec 2006 17:29:43 +0000 (17:29 +0000)
Will check if I can solve this with less changes in 1.2.

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@48270 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index eb381a7e294884b4aaa6aa3e8384c9cd24c5844b..ccf3911ea4793132af27a95edeb8105a877b6423 100644 (file)
@@ -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)) {