Merged revisions 100740 via svnmerge from
authorOlle Johansson <oej@edvina.net>
Tue, 29 Jan 2008 09:18:42 +0000 (09:18 +0000)
committerOlle Johansson <oej@edvina.net>
Tue, 29 Jan 2008 09:18:42 +0000 (09:18 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r100740 | oej | 2008-01-29 09:26:48 +0100 (Tis, 29 Jan 2008) | 8 lines

(closes issue #11736)
Reported by: MVF
Patches:
      bug11736-2.diff uploaded by oej (license 306)
Tested by: oej, MVF, revolution

(russellb: This was the showstopper for the release.)

........

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

channels/chan_sip.c

index ea3a27c..9f2cc3d 100644 (file)
@@ -964,6 +964,7 @@ struct sip_auth {
 #define SIP_PAGE2_RTCACHEFRIENDS       (1 << 0)        /*!< GP: Should we keep RT objects in memory for extended time? */
 #define SIP_PAGE2_RTAUTOCLEAR          (1 << 2)        /*!< GP: Should we clean memory from peers after expiry? */
 /* Space for addition of other realtime flags in the future */
 #define SIP_PAGE2_RTCACHEFRIENDS       (1 << 0)        /*!< GP: Should we keep RT objects in memory for extended time? */
 #define SIP_PAGE2_RTAUTOCLEAR          (1 << 2)        /*!< GP: Should we clean memory from peers after expiry? */
 /* Space for addition of other realtime flags in the future */
+#define SIP_PAGE2_STATECHANGEQUEUE     (1 << 9)        /*!< D: Unsent state pending change exists */
 
 #define SIP_PAGE2_VIDEOSUPPORT         (1 << 14)       /*!< DP: Video supported if offered? */
 #define SIP_PAGE2_TEXTSUPPORT          (1 << 15)       /*!< GDP: Global text enable */
 
 #define SIP_PAGE2_VIDEOSUPPORT         (1 << 14)       /*!< DP: Video supported if offered? */
 #define SIP_PAGE2_TEXTSUPPORT          (1 << 15)       /*!< GDP: Global text enable */
@@ -1262,7 +1263,7 @@ struct sip_pvt {
        int noncecount;                         /*!< Nonce-count */
        char lastmsg[256];                      /*!< Last Message sent/received */
        int amaflags;                           /*!< AMA Flags */
        int noncecount;                         /*!< Nonce-count */
        char lastmsg[256];                      /*!< Last Message sent/received */
        int amaflags;                           /*!< AMA Flags */
-       int pendinginvite;                      /*!< Any pending invite ? (seqno of this) */
+       int pendinginvite;                      /*!< Any pending INVITE or state NOTIFY (in subscribe pvt's) ? (seqno of this) */
        struct sip_request initreq;             /*!< Latest request that opened a new transaction
                                                        within this dialog.
                                                        NOT the request that opened the dialog
        struct sip_request initreq;             /*!< Latest request that opened a new transaction
                                                        within this dialog.
                                                        NOT the request that opened the dialog
@@ -8752,6 +8753,8 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
        add_header_contentLength(&req, tmp->used);
        add_line(&req, tmp->str);
 
        add_header_contentLength(&req, tmp->used);
        add_line(&req, tmp->str);
 
+       p->pendinginvite = p->ocseq;    /* Remember that we have a pending NOTIFY in order not to confuse the NOTIFY subsystem */
+
        return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
 }
 
        return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
 }
 
@@ -9992,10 +9995,17 @@ static int cb_extensionstate(char *context, char* exten, int state, void *data)
                p->laststate = state;
                break;
        }
                p->laststate = state;
                break;
        }
-       if (p->subscribed != NONE)      /* Only send state NOTIFY if we know the format */
-               transmit_state_notify(p, state, 1, FALSE);
-
-       ast_verb(2, "Extension Changed %s new state %s for Notify User %s\n", exten, ast_extension_state2str(state), p->username);
+       if (p->subscribed != NONE) {    /* Only send state NOTIFY if we know the format */
+               if (!p->pendinginvite) {
+                       transmit_state_notify(p, state, 1, FALSE);
+               } else {
+                       /* We already have a NOTIFY sent that is not answered. Queue the state up.
+                          if many state changes happen meanwhile, we will only send a notification of the last one */
+                       ast_set_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
+               }
+       }
+       ast_verb(2, "Extension Changed %s[%s] new state %s for Notify User %s %s\n", exten, context, ast_extension_state2str(state), p->username,
+                       ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE) ? "(queued)" : "");
 
        sip_pvt_unlock(p);
 
 
        sip_pvt_unlock(p);
 
@@ -14873,6 +14883,10 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
        else
                __sip_ack(p, seqno, 0, sipmethod);
 
        else
                __sip_ack(p, seqno, 0, sipmethod);
 
+       /* If this is a NOTIFY for a subscription clear the flag that indicates that we have a NOTIFY pending */
+       if (!p->owner && sipmethod == SIP_NOTIFY && p->pendinginvite) 
+               p->pendinginvite = 0;
+
        /* Get their tag if we haven't already */
        if (ast_strlen_zero(p->theirtag) || (resp >= 200)) {
                char tag[128];
        /* Get their tag if we haven't already */
        if (ast_strlen_zero(p->theirtag) || (resp >= 200)) {
                char tag[128];
@@ -14931,6 +14945,11 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                } else {
                                        if (p->subscribed == NONE) 
                                                p->needdestroy = 1;
                                } else {
                                        if (p->subscribed == NONE) 
                                                p->needdestroy = 1;
+                                       if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
+                                               /* Ready to send the next state we have on queue */
+                                               ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
+                                               cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
+                                       }
                                }
                        } else if (sipmethod == SIP_REGISTER) 
                                res = handle_response_register(p, resp, rest, req, seqno);
                                }
                        } else if (sipmethod == SIP_REGISTER) 
                                res = handle_response_register(p, resp, rest, req, seqno);