def __init__(self, add_trans_queue, global_update_queue, listen_port=5060):
        '''
        @type add_trans_queue: Queue
        @param add_trans_queue: A queue that this class will listen on for
            tuples of the form identical to the parameters to the
            add_transaction method of this class except with an extra parameter
            at the start that can be False to indicate to this class to shutdown
            or True otherwise. The data this queue receives will be added to the
            transaction list this class is monitoring
        @type global_update_queue: Queue
        @param global_update_queue: A queue that will receive a SIPTransaction
            object every time an update from the network arrives for that
            SIPTransaction
        '''

        self.add_trans_queue = add_trans_queue
        self.global_update_queue = global_update_queue
        self.listen_port = listen_port

        self.lock = thread.allocate_lock()
        self.transceiver = UDPTransceiver([self.listen_port], self.lock)
        self.transceiver.add_notify_queue(self.add_trans_queue,
                                          self.listen_port)
        self.transceiver.listen(True)

        # A dictionary mapping branch values to SIPTransaction objects
        self.transaction_dict = {}
        self.sip_parser = SIPParser()

        threading.Thread.__init__(self)
    def __init__(self, add_trans_queue, global_update_queue, listen_port=5060):
        '''
        @type add_trans_queue: Queue
        @param add_trans_queue: A queue that this class will listen on for
            tuples of the form identical to the parameters to the
            add_transaction method of this class except with an extra parameter
            at the start that can be False to indicate to this class to shutdown
            or True otherwise. The data this queue receives will be added to the
            transaction list this class is monitoring
        @type global_update_queue: Queue
        @param global_update_queue: A queue that will receive a SIPTransaction
            object every time an update from the network arrives for that
            SIPTransaction
        '''
        
        self.add_trans_queue = add_trans_queue
        self.global_update_queue = global_update_queue
        self.listen_port = listen_port

        self.lock = thread.allocate_lock()
        self.transceiver = UDPTransceiver([self.listen_port], self.lock)
        self.transceiver.add_notify_queue(self.add_trans_queue, self.listen_port)
        self.transceiver.listen(True)
        
        # A dictionary mapping branch values to SIPTransaction objects
        self.transaction_dict = {}
        self.sip_parser = SIPParser()

        threading.Thread.__init__(self)
class SIPTransactionManager(threading.Thread):
    def __init__(self, add_trans_queue, global_update_queue, listen_port=5060):
        '''
        @type add_trans_queue: Queue
        @param add_trans_queue: A queue that this class will listen on for
            tuples of the form identical to the parameters to the
            add_transaction method of this class except with an extra parameter
            at the start that can be False to indicate to this class to shutdown
            or True otherwise. The data this queue receives will be added to the
            transaction list this class is monitoring
        @type global_update_queue: Queue
        @param global_update_queue: A queue that will receive a SIPTransaction
            object every time an update from the network arrives for that
            SIPTransaction
        '''

        self.add_trans_queue = add_trans_queue
        self.global_update_queue = global_update_queue
        self.listen_port = listen_port

        self.lock = thread.allocate_lock()
        self.transceiver = UDPTransceiver([self.listen_port], self.lock)
        self.transceiver.add_notify_queue(self.add_trans_queue,
                                          self.listen_port)
        self.transceiver.listen(True)

        # A dictionary mapping branch values to SIPTransaction objects
        self.transaction_dict = {}
        self.sip_parser = SIPParser()

        threading.Thread.__init__(self)

    def run(self):
        while True:
            new_trans_tuple = None
            try:
                new_trans_tuple = self.add_trans_queue.get()
            except:
                pass

            if new_trans_tuple != None:
                #print >> sys.stderr,  'TM: Got data'
                if new_trans_tuple[0] == False:
                    #signal to listener first to exit
                    print >> stderr, 'tm returning cause tuple thingy was false'
                    print >> stderr, new_trans_tuple
                    return
                else:
                    data = new_trans_tuple[1]
                    source = new_trans_tuple[2]
                    addr = new_trans_tuple[3]
                    timeout = new_trans_tuple[4]
                    socket = None
                    # only interested in the socket if the data came from
                    # a source outside the core. Sources inside the core
                    # will be monitored by default
                    if source == EXTERNAL:
                        socket = new_trans_tuple[5]
                    elif source == GENERATOR:
                        print >> sys.stderr, 'got something from generator off queue'
                    self.add_data_to_transactions(data, source, addr,\
                                                   timeout, socket)

    def add_data_to_transactions(self,
                                 data,
                                 source,
                                 addr,
                                 timeout,
                                 socket=None):
        data_dict = self.sip_parser.parse(data)
        # no branch no fun
        if data_dict.has_key(sip_parser.BRANCH):
            t_data = TData(data, data_dict, source, addr, socket)
            self.add_transaction(t_data, timeout=timeout)

    def add_transaction(self, t_data, timeout=None):
        '''
        Function to add a SIP transaction to the list of the transactions
        this manager is taking care of. If a transaction with this branch
        already exists then this data and queue are appended to their lists
        and all other fields in the old sip_transaction are updated to
        the new values.

        If not a new SIPTransaction object is created with the provided details
        and added to the list.

        @type t_data: TData
        @param data: A TData object representing the data, its parsed fields and
            its origin
        @type timeout: Integer
        @param timeout: A timeout after which this transaction will no
            longer be monitored
        '''

        # parse all fields
        timestamp = time.time()
        data_dict = t_data.p_data

        # First identify the transaction the data is for or create a new
        # transaction for it
        t_data_added = False
        if self.transaction_dict.has_key(data_dict[sip_parser.BRANCH]):
            sip_t = self.transaction_dict[data_dict[sip_parser.BRANCH]]
            t_data_added = sip_t.add_response(t_data)

            if timeout: sip_t.timeout = timeout
        else:
            # If the source is the network then check that the request is
            # of a type that is allowed to create a new transaction. For
            # now we only allow a few types. More may be added in the future if required

            try:
                r_code = data_dict[sip_parser.RCODE]
            except KeyError:
                # Some of our fuzz requests will not have a request code
                # matching the defined pattern due to fuzzing but thats OK
                r_code = -1

            if t_data.source != NETWORK or (r_code <= sip_parser.r_INVITE
                                            and r_code >= sip_parser.r_CANCEL):
                sip_t = SIPTransaction(data_dict[sip_parser.BRANCH], [t_data], \
                                       timestamp, timeout)
                self.transaction_dict[data_dict[sip_parser.BRANCH]] = sip_t
            else:
                return

        # Now perform some actions based on the source of the data
        if t_data.source == GENERATOR:
            # Data was generated by the SIP backend. Send it and add the socket
            # used to the list being monitored
            print >> sys.stderr, 'Source is generator. Sending'
            send_sock = self.transceiver.send(t_data.data, t_data.addr)
            if send_sock:
                sip_t.sockets.append(send_sock)
        elif t_data.source == NETWORK and t_data_added:
            # Data originated from another node on the network. Put on the
            # notify queue. A copy is used in case another update arrives
            # before this one is processed and cloaks this one in the t_data list
            self.global_update_queue.put(deepcopy(sip_t))
        elif t_data.source == EXTERNAL:
            # Data came from an external source e.g the fuzzer and has already
            # been sent. We just need to monitor for responses
            if t_data.socket:
                sip_t.sockets.append(t_data.socket)
                self.transceiver.add_socket(t_data.socket)

        self.__check_timeouts()

    def __check_timeouts(self):
        '''
        Checks to see if any of the transactions have timed out and Removes
        them if so
        '''

        curr_time = time.time()
        print >> sys.stderr, 'TM: %d transactions being monitored' % len(
            self.transaction_dict)
        for branch in self.transaction_dict.keys():
            transaction = self.transaction_dict[branch]
            if curr_time - transaction.timestamp >= transaction.timeout:
                for sock in transaction.sockets:
                    self.transceiver.close_socket(sock)
                del self.transaction_dict[branch]

    def unregister_from_transceiver(self):
        '''
        Function to remove this transaction managers queue from the
        list of queues registered with the transceiver
        '''

        self.transceiver.remove_notify_queue(
            (self.incoming_data_queue, self.listen_port))
's=Opal SIP Session',
'c=IN IP4 192.168.3.102',
't=0 0',
'm=audio 5040 RTP/AVP 101 96 3 107 110 0 8',
'a=rtpmap:101 telephone-event/8000',
'a=fmtp:101 0-15',
'a=rtpmap:96 SPEEX/-1',
'a=rtpmap:3 GSM/8000',
'a=rtpmap:107 MS-GSM/8000',
'a=rtpmap:110 SPEEX/-1',
'a=rtpmap:0 PCMU/8000',
'a=rtpmap:8 PCMA/8000',
'm=video 5042 RTP/AVP 31',
'a=rtpmap:31 H261/-1']) + '\r\n'

cancel1 = '\r\n'.join(['CANCEL sip:[email protected] SIP/2.0',
'CSeq: 1 CANCEL',
'Via: SIP/2.0/UDP 192.168.3.102:5071;branch=z9hG4bKa8f5f4da-d867-dc11-8c7d-000c29da463b;rport',
'To: <sip:[email protected]>',                       
'From: "nnp nnp" <sip:[email protected]>;tag=a68cf4d7-d867-dc11-8c7d-000c29da463b',
'Call-ID: MOFOID@ubuntu',
'Max-Forwards: 70']) + '\r\n\r\n'

data_dict = SIPParser().parse(invite1)
t_data = TData(invite1, data_dict, None)

s_canceler= SIPCanceler(None, None)
cancel_request = s_canceler.create_cancel(t_data)
assert(cancel_request == cancel1)

class SIPTransactionManager(threading.Thread):
    def __init__(self, add_trans_queue, global_update_queue, listen_port=5060):
        '''
        @type add_trans_queue: Queue
        @param add_trans_queue: A queue that this class will listen on for
            tuples of the form identical to the parameters to the
            add_transaction method of this class except with an extra parameter
            at the start that can be False to indicate to this class to shutdown
            or True otherwise. The data this queue receives will be added to the
            transaction list this class is monitoring
        @type global_update_queue: Queue
        @param global_update_queue: A queue that will receive a SIPTransaction
            object every time an update from the network arrives for that
            SIPTransaction
        '''
        
        self.add_trans_queue = add_trans_queue
        self.global_update_queue = global_update_queue
        self.listen_port = listen_port

        self.lock = thread.allocate_lock()
        self.transceiver = UDPTransceiver([self.listen_port], self.lock)
        self.transceiver.add_notify_queue(self.add_trans_queue, self.listen_port)
        self.transceiver.listen(True)
        
        # A dictionary mapping branch values to SIPTransaction objects
        self.transaction_dict = {}
        self.sip_parser = SIPParser()

        threading.Thread.__init__(self)

    def run(self):
        while True:
            new_trans_tuple = None
            try:
                new_trans_tuple = self.add_trans_queue.get()
            except:
                pass

            if new_trans_tuple != None:
                #print >> sys.stderr,  'TM: Got data'
                if new_trans_tuple[0] == False:
                    #signal to listener first to exit
                    print >>stderr, 'tm returning cause tuple thingy was false'
                    print >>stderr, new_trans_tuple
                    return
                else:                    
                    data = new_trans_tuple[1]
                    source = new_trans_tuple[2]
                    addr = new_trans_tuple[3]
                    timeout = new_trans_tuple[4]
                    socket = None
                    # only interested in the socket if the data came from
                    # a source outside the core. Sources inside the core
                    # will be monitored by default
                    if source == EXTERNAL:
                        socket = new_trans_tuple[5]
                    elif source == GENERATOR:
                        print >>sys.stderr, 'got something from generator off queue'
                    self.add_data_to_transactions(data, source, addr,\
                                                   timeout, socket)
            
    def add_data_to_transactions(self, data, source, addr, timeout, socket=None):
        data_dict = self.sip_parser.parse(data)
        # no branch no fun
        if data_dict.has_key(sip_parser.BRANCH):
            t_data = TData(data, data_dict, source, addr, socket)
            self.add_transaction(t_data, timeout=timeout)

    def add_transaction(self, t_data, timeout=None):
        '''
        Function to add a SIP transaction to the list of the transactions
        this manager is taking care of. If a transaction with this branch
        already exists then this data and queue are appended to their lists
        and all other fields in the old sip_transaction are updated to
        the new values.

        If not a new SIPTransaction object is created with the provided details
        and added to the list.

        @type t_data: TData
        @param data: A TData object representing the data, its parsed fields and
            its origin
        @type timeout: Integer
        @param timeout: A timeout after which this transaction will no
            longer be monitored
        '''

        # parse all fields
        timestamp = time.time()
        data_dict = t_data.p_data

        # First identify the transaction the data is for or create a new
        # transaction for it
        t_data_added = False
        if self.transaction_dict.has_key(data_dict[sip_parser.BRANCH]):
            sip_t = self.transaction_dict[data_dict[sip_parser.BRANCH]]
            t_data_added = sip_t.add_response(t_data)
                    
            if timeout: sip_t.timeout = timeout
        else:
            # If the source is the network then check that the request is
            # of a type that is allowed to create a new transaction. For
            # now we only allow a few types. More may be added in the future if required

            try:                
                r_code = data_dict[sip_parser.RCODE]
            except KeyError:
                # Some of our fuzz requests will not have a request code
                # matching the defined pattern due to fuzzing but thats OK
                r_code = -1
                
            if t_data.source != NETWORK or (r_code <= sip_parser.r_INVITE and
                                             r_code >= sip_parser.r_CANCEL):
                sip_t = SIPTransaction(data_dict[sip_parser.BRANCH], [t_data], \
                                       timestamp, timeout)
                self.transaction_dict[data_dict[sip_parser.BRANCH]] = sip_t
            else:
                return
            
        # Now perform some actions based on the source of the data
        if t_data.source == GENERATOR:
            # Data was generated by the SIP backend. Send it and add the socket
            # used to the list being monitored
            print >> sys.stderr, 'Source is generator. Sending'
            send_sock = self.transceiver.send(t_data.data, t_data.addr)
            if send_sock:
                sip_t.sockets.append(send_sock)
        elif t_data.source == NETWORK and t_data_added:
            # Data originated from another node on the network. Put on the
            # notify queue. A copy is used in case another update arrives
            # before this one is processed and cloaks this one in the t_data list        
            self.global_update_queue.put(deepcopy(sip_t))
        elif t_data.source == EXTERNAL:
            # Data came from an external source e.g the fuzzer and has already
            # been sent. We just need to monitor for responses
            if t_data.socket:
                sip_t.sockets.append(t_data.socket)
                self.transceiver.add_socket(t_data.socket)
                
        self.__check_timeouts()

    def __check_timeouts(self):
        '''
        Checks to see if any of the transactions have timed out and Removes
        them if so
        '''

        curr_time = time.time()
        print >>sys.stderr, 'TM: %d transactions being monitored' % len(self.transaction_dict)
        for branch in self.transaction_dict.keys():
            transaction = self.transaction_dict[branch]
            if curr_time - transaction.timestamp >= transaction.timeout:
                for sock in transaction.sockets:    
                    self.transceiver.close_socket(sock)
                del self.transaction_dict[branch]
        
    def unregister_from_transceiver(self):
        '''
        Function to remove this transaction managers queue from the
        list of queues registered with the transceiver
        '''
        
        self.transceiver.remove_notify_queue((self.incoming_data_queue, self.listen_port))