예제 #1
0
def _matchToDialog(msg, origin, dest, dialogs):
    dialog= dialogs.get(
        (msg.headers['call-id'][0],
         parseAddress(msg.headers[origin][0])[2].get('tag',''),
         parseAddress(msg.headers[dest][0])[2].get('tag','')),
        None)
    return dialog
예제 #2
0
 def _findDest(self, msg):
     rs = msg.headers.get('route', None)
     if rs:
         dest = parseAddress(rs[0])[1]
     else:
         dest = self.remoteAddress[1]
     return dest
예제 #3
0
    def forServer(cls, tu, contactURI, msg):
        """
        Create a dialog from a received INVITE.

        tu: the transaction user handling this dialog.
        contactURI: the contact for the other party.
        msg: the initial INVITE that establishes this dialog.
        """
        #RFC 3261 12.1.1
        self = cls(tu, contactURI)
        self.msg = msg
        toAddress, fromAddress = self._finishInit()
        self.localAddress = toAddress
        self.remoteAddress = fromAddress
        self.localAddress[2]['tag'] = self.genTag()
        self.direction = "server"
        self.routeSet = [
            parseAddress(route)
            for route in self.msg.headers.get('record-route', [])
        ]
        self.clientState = "confirmed"

        def gotRTP(rtp):
            self.rtp = rtp
            return self.rtp.createRTPSocket(self, contactURI.host)

        def gotCookie(c):
            self.cookie = c
            return self

        return self.tu.mediaController.getProcess().addCallback(
            gotRTP).addCallback(gotCookie)
예제 #4
0
    def forServer(cls, tu, contactURI, msg):
        """
        Create a dialog from a received INVITE.

        tu: the transaction user handling this dialog.
        contactURI: the contact for the other party.
        msg: the initial INVITE that establishes this dialog.
        """
        #RFC 3261 12.1.1
        self = cls(tu, contactURI)
        self.msg = msg
        toAddress, fromAddress = self._finishInit()
        self.localAddress = toAddress
        self.remoteAddress = fromAddress
        self.localAddress[2]['tag'] = self.genTag()
        self.direction = "server"
        self.routeSet = [parseAddress(route) for route in self.msg.headers.get('record-route', [])]
        self.clientState = "confirmed"
        def gotRTP(rtp):
            self.rtp = rtp
            return self.rtp.createRTPSocket(self, contactURI.host)
        def gotCookie(c):
            self.cookie = c
            return self
        return self.tu.mediaController.getProcess().addCallback(gotRTP).addCallback(gotCookie)
예제 #5
0
    def requestReceived(self, msg, addr):
        #RFC 3261 12.2.2
        if msg.method == "INVITE":
            st = ServerInviteTransaction(self.transport, self, msg, addr)
        else:
            st = ServerTransaction(self.transport, self, msg, addr)
        #dialog checking
        dialog = matchRequestToDialog(msg, self.dialogs)

        #untagged requests must be checked against ongoing transactions
        # see 8.2.2.2


        if not dialog and parseAddress(msg.headers['to'][0])[2].get('tag',None):
            #uh oh, there was an expectation of a dialog
            #but we can't remember it (maybe we crashed?)
            st.messageReceivedFromTU(responseFromRequest(481, msg))
            return defer.succeed(st)
            #authentication
            #check for Require
        m = getattr(self, "process_" + msg.method, None)
        if not m:
            st.messageReceivedFromTU(responseFromRequest(405, msg))
            return defer.succeed(st)
        else:
            return defer.maybeDeferred(m, st, msg, addr, dialog).addCallback(
                lambda x: st)
예제 #6
0
        def lookupElement(dialog):

            avatar = self.voicesystem.localElementByName(
                parseAddress(msg.headers['to'][0])[1].username)

            dialog.callController = avatar.buildCallController(dialog)
            if msg.body:
                sdp = SDP(msg.body)
            else:
                sdp = None
            d = defer.maybeDeferred(dialog.rtp.getSDP, dialog, sdp)

            def gotSDP(mysdp):
                dialog.sessionDescription = mysdp
                if not mysdp.hasMediaDescriptions():
                    st.messageReceivedFromTU(responseFromRequest(406, msg))
                    return st
                if sdp:
                    self.maybeStartAudio(dialog, sdp)
                self.dialogs[dialog.getDialogID()] = dialog
                response = dialog.responseFromRequest(200, msg, mysdp.show())
                st.messageReceivedFromTU(response)

                dialog.ackTimerRetry(response)

            d.addCallback(gotSDP)
            return d
예제 #7
0
    def requestReceived(self, msg, addr):
        #RFC 3261 12.2.2
        if msg.method == "INVITE":
            st = ServerInviteTransaction(self.transport, self, msg, addr)
        else:
            st = ServerTransaction(self.transport, self, msg, addr)
        #dialog checking
        dialog = matchRequestToDialog(msg, self.dialogs)

        #untagged requests must be checked against ongoing transactions
        # see 8.2.2.2

        if not dialog and parseAddress(msg.headers['to'][0])[2].get(
                'tag', None):
            #uh oh, there was an expectation of a dialog
            #but we can't remember it (maybe we crashed?)
            st.messageReceivedFromTU(responseFromRequest(481, msg))
            return defer.succeed(st)
            #authentication
            #check for Require
        m = getattr(self, "process_" + msg.method, None)
        if not m:
            st.messageReceivedFromTU(responseFromRequest(405, msg))
            return defer.succeed(st)
        else:
            return defer.maybeDeferred(m, st, msg, addr,
                                       dialog).addCallback(lambda x: st)
예제 #8
0
    def responseReceived(self, response, ct=None):

        #OK this function is a bit hairy because I don't want to track
        #any call state in this class and responses to various things
        #need to be handled differently. The main event is 2xx
        #responses to the INVITE -- that changes the early dialog
        #(created when the INVITE was sent) to an confirmed dialog.
        #Error responses result in dialog teardown, as do responses to BYEs.

        #RFC 3261 12.2.1.2
        dialog = self.cts.get(ct, None)
        if dialog is None:
            dialog = matchResponseToDialog(response, self.dialogs)


        if 'INVITE' in response.headers['cseq'][0] and 200 <= response.code < 300:
            #possibly this line doesn't belong here? earlyResponseReceived
            #does it too but IIRC it can't come before sending the ack
            dialog.remoteAddress = parseAddress(response.headers['to'][0])
            self.acknowledgeInvite(dialog, response)

        if dialog.clientState == "early":
            self.earlyResponseReceived(dialog, response, ct)

        if dialog.clientState == "byeSent":
            self.byeResponseReceived(dialog, response, ct)
        elif dialog.clientState == "reinviteSent":
            self.reinviteResponseReceived(dialog, response, ct)
예제 #9
0
    def lookupProcessor(self, msg, dialogs):
        if isinstance(msg, sip.Request) and msg.method == "REGISTER":
            #not our dept
            return defer.succeed(None)

        for name, domain in userbase.getAccountNames(self.store, protocol=u'sip'):
            if name == sip.parseAddress(msg.headers["to"][0])[1].username:
                contact = sip.IContact(self.store)
                def regged(_):
                    return defer.succeed(None)
                def unregged(e):
                    self.uas.dialogs = dialogs
                    return self.uas
                return defer.maybeDeferred(contact.getRegistrationInfo, sip.parseAddress(msg.headers["from"][0])[1]).addCallbacks(regged, unregged)
        else:
            return defer.succeed(None)
예제 #10
0
    def responseReceived(self, response, ct=None):

        #OK this function is a bit hairy because I don't want to track
        #any call state in this class and responses to various things
        #need to be handled differently. The main event is 2xx
        #responses to the INVITE -- that changes the early dialog
        #(created when the INVITE was sent) to an confirmed dialog.
        #Error responses result in dialog teardown, as do responses to BYEs.

        #RFC 3261 12.2.1.2
        dialog = self.cts.get(ct, None)
        if dialog is None:
            dialog = matchResponseToDialog(response, self.dialogs)

        if 'INVITE' in response.headers['cseq'][
                0] and 200 <= response.code < 300:
            #possibly this line doesn't belong here? earlyResponseReceived
            #does it too but IIRC it can't come before sending the ack
            dialog.remoteAddress = parseAddress(response.headers['to'][0])
            self.acknowledgeInvite(dialog, response)

        if dialog.clientState == "early":
            self.earlyResponseReceived(dialog, response, ct)

        if dialog.clientState == "byeSent":
            self.byeResponseReceived(dialog, response, ct)
        elif dialog.clientState == "reinviteSent":
            self.reinviteResponseReceived(dialog, response, ct)
예제 #11
0
 def _findDest(self, msg):
     rs = msg.headers.get('route', None)
     if rs:
         dest = parseAddress(rs[0])[1]
     else:
         dest = self.remoteAddress[1]
     return dest
예제 #12
0
 def earlyResponseReceived(self, dialog, response, ct):
     if 200 <= response.code < 300:
         #RFC 3261 12.1.2
         dialog.clientState = "confirmed"
         dialog.remoteAddress = parseAddress(response.headers['to'][0])
         dialog.routeSet = [parseAddress(route) for route in response.headers.get('record-route', [])[::-1]]
         self.dialogs[dialog.getDialogID()] = dialog
         sdp = SDP(response.body)
         self.maybeStartAudio(dialog, sdp)
         if self.controller:
             self.controller.callBegan(dialog)
     elif 300 <= response.code < 400:
         raise NotImplemented, "Dunno about redirects yet"
     elif 400 <= response.code < 700:
         if dialog.getDialogID() in self.dialogs:
             del self.dialogs[dialog.getDialogID()]
         del self.cts[ct]
         self.controller.callFailed(dialog, response)
예제 #13
0
 def earlyResponseReceived(self, dialog, response, ct):
     if 200 <= response.code < 300:
         #RFC 3261 12.1.2
         dialog.clientState = "confirmed"
         dialog.remoteAddress = parseAddress(response.headers['to'][0])
         dialog.routeSet = [
             parseAddress(route)
             for route in response.headers.get('record-route', [])[::-1]
         ]
         self.dialogs[dialog.getDialogID()] = dialog
         sdp = SDP(response.body)
         self.maybeStartAudio(dialog, sdp)
         if self.controller:
             self.controller.callBegan(dialog)
     elif 300 <= response.code < 400:
         raise NotImplemented, "Dunno about redirects yet"
     elif 400 <= response.code < 700:
         if dialog.getDialogID() in self.dialogs:
             del self.dialogs[dialog.getDialogID()]
         del self.cts[ct]
         self.controller.callFailed(dialog, response)
예제 #14
0
    def fuzzyMatch(self, first, second):
        "try to ignore bits randomly generated by our code"
        self.assertEqual(first.__class__, second.__class__)
        self.assertEqual(first.version, second.version)
        if isinstance(first, sip.Request):
            self.assertEqual(first.method, second.method)
            self.assertEqual(first.uri, second.uri)
        else:
            self.assertEqual(first.code, second.code)

        for header in first.headers.keys():
            if not second.headers.get(header):
                if not first.headers[header]:
                    #woops, it's empty, never mind
                    continue
                raise unittest.FailTest("%s not present in %s" % (header, second))
            if header in ('from', 'to', 'contact'):
                #strip tags
                if isinstance(first.headers[header][0], sip.URL):
                    firsturl = first.headers[header][0]
                else:
                    firsturl = sip.parseAddress(first.headers[header][0])[1]
                secondurl = sip.parseAddress(second.headers[header][0])[1]
                self.assertEqual(firsturl, secondurl)
            elif header == "via":
                firstvia = [sip.parseViaHeader(h)
                            for h in first.headers['via']]
                secondvia = [sip.parseViaHeader(h)
                            for h in second.headers['via']]
                #convert to strings for easy reading of output
                self.assertEqual([x.toString() for x in firstvia],
                                 [x.toString() for x in firstvia])
            elif header == "content-length":
                continue
            else:
                self.assertEqual([str(x) for x in first.headers[header]],
                                 [str(x) for x in second.headers[header]])
예제 #15
0
 def reinviteResponseReceived(self, dialog, response, ct):
     if response.code == 491:
         if dialog.direction == "client":
             reactor.callLater(random.randint(210,400)/100.0,
                               dialog._sendReinvite, dialog.reinviteMsg)
         else:
             reactor.callLater(random.randint(0, 200)/100.0,
                               dialog._sendReinvite, dialog.reinviteMsg)
     elif 200 <= response.code < 300:
         dialog.clientState = "confirmed"
         dialog.msg = dialog.reinviteMsg
         dialog.contactURI = parseAddress(dialog.msg.headers['contact'][0])[1]
         dialog.sessionDescription = dialog.reinviteSDP
     else:
         dialog.clientState = "confirmed"
예제 #16
0
            def gotSDP(mysdp):
                if not mysdp.hasMediaDescriptions():
                    st.messageReceivedFromTU(responseFromRequest(488, msg))
                    return st
                dialog.sessionDescription = mysdp
                if dialog.clientState == "reinviteSent":
                    st.messageReceivedFromTU(dialog.responseFromRequest(491, msg))
                else:
                    if sdp:
                        self.maybeStartAudio(dialog, sdp)
                    dialog.msg = msg
                    dialog.reinviteMsg = True
                    dialog.remoteAddress = parseAddress(msg.headers['from'][0])
                    response = dialog.responseFromRequest(200, msg, mysdp.show())
                    st.messageReceivedFromTU(response)
                    dialog.ackTimerRetry(response)

                return st
예제 #17
0
    def generateRequest(self, method):
        #RFC 3261 12.2.1.1
        r = Request(method, self.remoteAddress[1])

        if self.routeSet:
            r.headers['route'] = [formatAddress(route) for route in self.routeSet]
            if 'lr' not in self.routeSet[0][1].other:
                r.headers['route'].append(formatAddress(("", r.uri, {})))
                r.uri = parseAddress(r.headers['route'].pop())[1]

        r.addHeader('to', formatAddress(self.remoteAddress))
        r.addHeader('from', formatAddress(self.localAddress))
        r.addHeader('cseq', "%s %s" % (self.localCSeq, method))
        self.localCSeq += 1
        r.addHeader('call-id', self.msg.headers['call-id'][0])
        r.addHeader('contact', formatAddress(self.contactURI))
        r.addHeader('content-length', 0)
        return r
예제 #18
0
 def reinviteResponseReceived(self, dialog, response, ct):
     if response.code == 491:
         if dialog.direction == "client":
             reactor.callLater(
                 random.randint(210, 400) / 100.0, dialog._sendReinvite,
                 dialog.reinviteMsg)
         else:
             reactor.callLater(
                 random.randint(0, 200) / 100.0, dialog._sendReinvite,
                 dialog.reinviteMsg)
     elif 200 <= response.code < 300:
         dialog.clientState = "confirmed"
         dialog.msg = dialog.reinviteMsg
         dialog.contactURI = parseAddress(
             dialog.msg.headers['contact'][0])[1]
         dialog.sessionDescription = dialog.reinviteSDP
     else:
         dialog.clientState = "confirmed"
예제 #19
0
    def generateRequest(self, method):
        #RFC 3261 12.2.1.1
        r = Request(method, self.remoteAddress[1])

        if self.routeSet:
            r.headers['route'] = [
                formatAddress(route) for route in self.routeSet
            ]
            if 'lr' not in self.routeSet[0][1].other:
                r.headers['route'].append(formatAddress(("", r.uri, {})))
                r.uri = parseAddress(r.headers['route'].pop())[1]

        r.addHeader('to', formatAddress(self.remoteAddress))
        r.addHeader('from', formatAddress(self.localAddress))
        r.addHeader('cseq', "%s %s" % (self.localCSeq, method))
        self.localCSeq += 1
        r.addHeader('call-id', self.msg.headers['call-id'][0])
        r.addHeader('contact', formatAddress(self.contactURI))
        r.addHeader('content-length', 0)
        return r
예제 #20
0
            def gotSDP(mysdp):
                if not mysdp.hasMediaDescriptions():
                    st.messageReceivedFromTU(responseFromRequest(488, msg))
                    return st
                dialog.sessionDescription = mysdp
                if dialog.clientState == "reinviteSent":
                    st.messageReceivedFromTU(
                        dialog.responseFromRequest(491, msg))
                else:
                    if sdp:
                        self.maybeStartAudio(dialog, sdp)
                    dialog.msg = msg
                    dialog.reinviteMsg = True
                    dialog.remoteAddress = parseAddress(msg.headers['from'][0])
                    response = dialog.responseFromRequest(
                        200, msg, mysdp.show())
                    st.messageReceivedFromTU(response)
                    dialog.ackTimerRetry(response)

                return st
예제 #21
0
        def lookupElement(dialog):

            avatar = self.voicesystem.localElementByName(parseAddress(msg.headers['to'][0])[1].username)

            dialog.callController = avatar.buildCallController(dialog)
            if msg.body:
                sdp = SDP(msg.body)
            else:
                sdp = None
            d = defer.maybeDeferred(dialog.rtp.getSDP, dialog, sdp)
            def gotSDP(mysdp):
                dialog.sessionDescription = mysdp
                if not mysdp.hasMediaDescriptions():
                    st.messageReceivedFromTU(responseFromRequest(406, msg))
                    return st
                if sdp:
                    self.maybeStartAudio(dialog, sdp)
                self.dialogs[dialog.getDialogID()] = dialog
                response = dialog.responseFromRequest(200, msg, mysdp.show())
                st.messageReceivedFromTU(response)

                dialog.ackTimerRetry(response)
            d.addCallback(gotSDP)
            return d
예제 #22
0
    def test3PCC(self):

        self.svc.setupCallBetween(sip.parseAddress("sip:[email protected]"),
                                  sip.parseAddress("sip:[email protected]"))
예제 #23
0
    def process_INVITE(self, st, msg, addr, dialog):
        #RFC 3261 13.3.1
        if dialog:
            #it's a reinvite
            if msg.body:
                #new SDP ahoy
                sdp = SDP(msg.body)
            else:
                sdp = None
            d = defer.maybeDeferred(dialog.rtp.getSDP, dialog, sdp)
            def gotSDP(mysdp):
                if not mysdp.hasMediaDescriptions():
                    st.messageReceivedFromTU(responseFromRequest(488, msg))
                    return st
                dialog.sessionDescription = mysdp
                if dialog.clientState == "reinviteSent":
                    st.messageReceivedFromTU(dialog.responseFromRequest(491, msg))
                else:
                    if sdp:
                        self.maybeStartAudio(dialog, sdp)
                    dialog.msg = msg
                    dialog.reinviteMsg = True
                    dialog.remoteAddress = parseAddress(msg.headers['from'][0])
                    response = dialog.responseFromRequest(200, msg, mysdp.show())
                    st.messageReceivedFromTU(response)
                    dialog.ackTimerRetry(response)

                return st
            return d.addCallback(gotSDP)
        #otherwise, time to start a new dialog

        d = Dialog.forServer(self, URL(self.host,
                             parseAddress(msg.headers['to'][0])[1].username),
                             msg)


        def lookupElement(dialog):

            avatar = self.voicesystem.localElementByName(parseAddress(msg.headers['to'][0])[1].username)

            dialog.callController = avatar.buildCallController(dialog)
            if msg.body:
                sdp = SDP(msg.body)
            else:
                sdp = None
            d = defer.maybeDeferred(dialog.rtp.getSDP, dialog, sdp)
            def gotSDP(mysdp):
                dialog.sessionDescription = mysdp
                if not mysdp.hasMediaDescriptions():
                    st.messageReceivedFromTU(responseFromRequest(406, msg))
                    return st
                if sdp:
                    self.maybeStartAudio(dialog, sdp)
                self.dialogs[dialog.getDialogID()] = dialog
                response = dialog.responseFromRequest(200, msg, mysdp.show())
                st.messageReceivedFromTU(response)

                dialog.ackTimerRetry(response)
            d.addCallback(gotSDP)
            return d

        def failedLookup(err):
            err.trap(NoSuchUser, UnauthorizedLogin)
            raise SIPLookupError(604)

        return d.addCallback(lookupElement).addErrback(failedLookup)
예제 #24
0
 def _finishInit(self):
     self.callID = self.msg.headers['call-id'][0]
     toAddress = parseAddress(self.msg.headers['to'][0])
     fromAddress = parseAddress(self.msg.headers['from'][0])
     return toAddress, fromAddress
예제 #25
0
    def process_INVITE(self, st, msg, addr, dialog):
        #RFC 3261 13.3.1
        if dialog:
            #it's a reinvite
            if msg.body:
                #new SDP ahoy
                sdp = SDP(msg.body)
            else:
                sdp = None
            d = defer.maybeDeferred(dialog.rtp.getSDP, dialog, sdp)

            def gotSDP(mysdp):
                if not mysdp.hasMediaDescriptions():
                    st.messageReceivedFromTU(responseFromRequest(488, msg))
                    return st
                dialog.sessionDescription = mysdp
                if dialog.clientState == "reinviteSent":
                    st.messageReceivedFromTU(
                        dialog.responseFromRequest(491, msg))
                else:
                    if sdp:
                        self.maybeStartAudio(dialog, sdp)
                    dialog.msg = msg
                    dialog.reinviteMsg = True
                    dialog.remoteAddress = parseAddress(msg.headers['from'][0])
                    response = dialog.responseFromRequest(
                        200, msg, mysdp.show())
                    st.messageReceivedFromTU(response)
                    dialog.ackTimerRetry(response)

                return st

            return d.addCallback(gotSDP)
        #otherwise, time to start a new dialog

        d = Dialog.forServer(
            self, URL(self.host,
                      parseAddress(msg.headers['to'][0])[1].username), msg)

        def lookupElement(dialog):

            avatar = self.voicesystem.localElementByName(
                parseAddress(msg.headers['to'][0])[1].username)

            dialog.callController = avatar.buildCallController(dialog)
            if msg.body:
                sdp = SDP(msg.body)
            else:
                sdp = None
            d = defer.maybeDeferred(dialog.rtp.getSDP, dialog, sdp)

            def gotSDP(mysdp):
                dialog.sessionDescription = mysdp
                if not mysdp.hasMediaDescriptions():
                    st.messageReceivedFromTU(responseFromRequest(406, msg))
                    return st
                if sdp:
                    self.maybeStartAudio(dialog, sdp)
                self.dialogs[dialog.getDialogID()] = dialog
                response = dialog.responseFromRequest(200, msg, mysdp.show())
                st.messageReceivedFromTU(response)

                dialog.ackTimerRetry(response)

            d.addCallback(gotSDP)
            return d

        def failedLookup(err):
            err.trap(NoSuchUser, UnauthorizedLogin)
            raise SIPLookupError(604)

        return d.addCallback(lookupElement).addErrback(failedLookup)
예제 #26
0
 def _finishInit(self):
     self.callID = self.msg.headers['call-id'][0]
     toAddress = parseAddress(self.msg.headers['to'][0])
     fromAddress = parseAddress(self.msg.headers['from'][0])
     return toAddress, fromAddress
예제 #27
0
def _matchToDialog(msg, origin, dest, dialogs):
    dialog = dialogs.get(
        (msg.headers['call-id'][0], parseAddress(
            msg.headers[origin][0])[2].get('tag', ''),
         parseAddress(msg.headers[dest][0])[2].get('tag', '')), None)
    return dialog