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))