def gotConnection(conn, username, password): yield conn.authenticate(username, password) chan = yield conn.channel(1) yield chan.channel_open() DeliverSmPDU = DeliverSM( source_addr = '584141111330', destination_addr = '24247', short_message = 'Prueba 01 !', seqNum = 1,) content = DeliverSmContent(DeliverSmPDU, 'SIMULATOR' ) #print DeliverSmPDU yield chan.basic_publish(exchange='messaging', routing_key='deliver.sm.SIMULATOR', content=content) # A clean way to tear down and stop yield chan.channel_close() chan0 = yield conn.channel(0) yield chan0.connection_close() reactor.stop()
def test_normal_nopickling(self): c = DeliverSmContent(self.body, 'connector1', prePickle=False) self.assertEquals(c.body, self.body) self.assertEquals(c['headers']['connector-id'], 'connector1') self.assertEquals(c['headers']['concatenated'], False) self.assertFalse(c['message-id'] == None)
def gotConnection(conn, username, password,src,dest,text): yield conn.authenticate(username, password) #print 'Connected to RabbitMQ' chan = yield conn.channel(1) yield chan.channel_open() DeliverSmPDU = DeliverSM( source_addr = src, source_addr_ton = AddrTon.NATIONAL, source_addr_npi = AddrNpi.ISDN, destination_addr = dest, dest_addr_ton = AddrTon.NATIONAL, dest_addr_npi = AddrNpi.ISDN, esm_class=EsmClass(EsmClassMode.DEFAULT, EsmClassType.DEFAULT), protocol_id=0, priority_flag=PriorityFlag.LEVEL_0, registered_delivery=RegisteredDelivery(RegisteredDeliveryReceipt.NO_SMSC_DELIVERY_RECEIPT_REQUESTED), replace_if_present_flag=ReplaceIfPresentFlag.DO_NOT_REPLACE, short_message = text, seqNum = 1,) content = DeliverSmContent(DeliverSmPDU, 'SIMULATOR' ) #print DeliverSmPDU yield chan.basic_publish(exchange='messaging', routing_key='deliver.sm.SIMULATOR', content=content) # A clean way to tear down and stop yield chan.channel_close() chan0 = yield conn.channel(0) yield chan0.connection_close()
def test_headers_concatenated(self): c = DeliverSmContent(self.body, 'connector1', prePickle=False, concatenated=True) self.assertEquals(c['headers']['concatenated'], True) self.assertFalse(c['message-id'] == None)
def test_normal_pickling(self): c = DeliverSmContent(self.body, 'connector1') self.assertNotEquals(c.body, self.body) self.assertEquals(c.body, pickle.dumps(self.body, 2)) self.assertEquals(c['headers']['connector-id'], 'connector1') self.assertEquals(c['headers']['concatenated'], False) self.assertFalse(c['message-id'] == None) self.assertTrue('created_at' in c['headers'])
def deliver_sm_event_post_interception(self, *args, **kw): """This event is called whenever a deliver_sm pdu is received through a SMPPc It will hand the pdu to the router or a dlr thrower (depending if its a DLR or not). Note: this event will catch data_sm pdus as well """ try: # Control args if 'smpp' not in kw or 'routable' not in kw: self.log.error( 'deliver_sm_event_post_interception missing arguments after interception: %s', kw) raise InterceptorRunError( 'deliver_sm_event_post_interception missing arguments after interception') # Set defaults smpp = kw['smpp'] routable = kw['routable'] if 'concatenated' in kw: concatenated = kw['concatenated'] else: concatenated = False # Get message_content if 'short_message' in routable.pdu.params and len(routable.pdu.params['short_message']) > 0: message_content = routable.pdu.params['short_message'] elif 'message_payload' in routable.pdu.params: message_content = routable.pdu.params['message_payload'] elif 'short_message' in routable.pdu.params: message_content = routable.pdu.params['short_message'] else: message_content = None # Post interception: if len(args) == 1: if isinstance(args[0], bool) and not args[0]: smpp.factory.stats.inc('interceptor_error_count') self.log.error('Failed running interception script, got a False return.') raise InterceptorRunError('Failed running interception script, check log for details') elif isinstance(args[0], dict) and args[0]['smpp_status'] > 0: smpp.factory.stats.inc('interceptor_error_count') self.log.info( 'Interceptor script returned %s smpp_status error.', args[0]['smpp_status']) raise DeliverSmInterceptionError(code=args[0]['smpp_status']) elif isinstance(args[0], str): smpp.factory.stats.inc('interceptor_count') routable = pickle.loads(args[0]) else: smpp.factory.stats.inc('interceptor_error_count') self.log.error( 'Failed running interception script, got the following return: %s', args[0]) raise InterceptorRunError( 'Failed running interception script, got the following return: %s' % args[0]) self.log.debug('Handling deliver_sm_event_post_interception event for smppc: %s', self.SMPPClientFactory.config.id) routable.pdu.dlr = self.SMPPOperationFactory.isDeliveryReceipt(routable.pdu) content = DeliverSmContent(routable, self.SMPPClientFactory.config.id, pickleProtocol=self.pickleProtocol, concatenated=concatenated) msgid = content.properties['message-id'] if routable.pdu.dlr is None: # We have a SMS-MO # UDH is set ? UDHI_INDICATOR_SET = False if 'esm_class' in routable.pdu.params and hasattr(routable.pdu.params['esm_class'], 'gsmFeatures'): for gsmFeature in routable.pdu.params['esm_class'].gsmFeatures: if str(gsmFeature) == 'UDHI_INDICATOR_SET': UDHI_INDICATOR_SET = True break splitMethod = None # Is it a part of a long message ? if 'sar_msg_ref_num' in routable.pdu.params: splitMethod = 'sar' total_segments = routable.pdu.params['sar_total_segments'] segment_seqnum = routable.pdu.params['sar_segment_seqnum'] msg_ref_num = routable.pdu.params['sar_msg_ref_num'] self.log.debug( 'Received SMS-MO part [queue-msgid:%s] using SAR: ttl_segments=%s, segment_sn=%s, msgref=%s', msgid, total_segments, segment_seqnum, msg_ref_num) elif UDHI_INDICATOR_SET and message_content[:3] == '\x05\x00\x03': splitMethod = 'udh' total_segments = struct.unpack('!B', message_content[4])[0] segment_seqnum = struct.unpack('!B', message_content[5])[0] msg_ref_num = struct.unpack('!B', message_content[3])[0] self.log.debug( 'Received SMS-MO part [queue-msgid:%s] using UDH: ttl_segments=%s, segment_sn=%s, msgref=%s', msgid, total_segments, segment_seqnum, msg_ref_num) if splitMethod is None: # It's a simple short message or a part of a concatenated message routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s] with routing_key[%s]", msgid, routing_key) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) # Get values from data_sm or deliver_sm priority_flag = None if 'priority_flag' in routable.pdu.params: priority_flag = routable.pdu.params['priority_flag'] validity_period = None if 'validity_period' in routable.pdu.params: validity_period = routable.pdu.params['validity_period'] self.log.info( "SMS-MO [cid:%s] [queue-msgid:%s] [status:%s] [prio:%s] [validity:%s] [from:%s] [to:%s] \ [content:%r]", self.SMPPClientFactory.config.id, msgid, routable.pdu.status, priority_flag, validity_period, routable.pdu.params['source_addr'], routable.pdu.params['destination_addr'], message_content) else: # Long message part received if self.redisClient is None: self.log.critical( 'Invalid RC found while receiving part of long DeliverSm [queue-msgid:%s], MSG IS LOST !', msgid) else: # Save it to redis hashKey = "longDeliverSm:%s:%s:%s" % ( self.SMPPClientFactory.config.id, msg_ref_num, routable.pdu.params['destination_addr']) hashValues = {'pdu': routable.pdu, 'total_segments': total_segments, 'msg_ref_num': msg_ref_num, 'segment_seqnum': segment_seqnum} yield self.redisClient.hset( hashKey, segment_seqnum, pickle.dumps(hashValues, self.pickleProtocol)).addCallback( self.concatDeliverSMs, hashKey, splitMethod, total_segments, msg_ref_num, segment_seqnum) self.log.info( "DeliverSmContent[%s] is part of long msg of (%s), will be enqueued after concatenation.", msgid, total_segments) # Flag it as "will_be_concatenated" and publish it to router routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s](flagged:wbc) with routing_key[%s]", msgid, routing_key) content.properties['headers']['will_be_concatenated'] = True yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) else: # This is a DLR ! # Send DLR to DLRLookup yield self.amqpBroker.publish(exchange='messaging', routing_key='dlr.deliver_sm', content=DLR(pdu_type=routable.pdu.id, msgid=self.code_dlr_msgid(routable.pdu), status=routable.pdu.dlr['stat'], cid=self.SMPPClientFactory.config.id, dlr_details=routable.pdu.dlr)) except (InterceptorRunError, DeliverSmInterceptionError) as e: self.log.info("SMS-MO [cid:%s] [i-status:%s] [from:%s] [to:%s] [content:%r]", self.SMPPClientFactory.config.id, e.status, routable.pdu.params['source_addr'], routable.pdu.params['destination_addr'], message_content) # Known exception handling defer.returnValue(DataHandlerResponse(status=e.status)) except Exception, e: # Unknown exception handling self.log.critical('Got an unknown exception (%s): %s', type(e), e) defer.returnValue(DataHandlerResponse(status=CommandStatus.ESME_RUNKNOWNERR))
def deliver_sm_event_post_interception(self, *args, **kw): """This event is called whenever a deliver_sm pdu is received through a SMPPc It will hand the pdu to the router or a dlr thrower (depending if its a DLR or not). Note: this event will catch data_sm pdus as well """ try: # Control args if 'smpp' not in kw or 'routable' not in kw: self.log.error( 'deliver_sm_event_post_interception missing arguments after interception: %s', kw) raise InterceptorRunError( 'deliver_sm_event_post_interception missing arguments after interception' ) # Set defaults smpp = kw['smpp'] routable = kw['routable'] if 'concatenated' in kw: concatenated = kw['concatenated'] else: concatenated = False # Get message_content if 'short_message' in routable.pdu.params and len( routable.pdu.params['short_message']) > 0: message_content = routable.pdu.params['short_message'] elif 'message_payload' in routable.pdu.params: message_content = routable.pdu.params['message_payload'] elif 'short_message' in routable.pdu.params: message_content = routable.pdu.params['short_message'] else: message_content = None # Post interception: if len(args) == 1: if isinstance(args[0], bool) and not args[0]: smpp.factory.stats.inc('interceptor_error_count') self.log.error( 'Failed running interception script, got a False return.' ) raise InterceptorRunError( 'Failed running interception script, check log for details' ) elif isinstance(args[0], dict) and args[0]['smpp_status'] > 0: smpp.factory.stats.inc('interceptor_error_count') self.log.info( 'Interceptor script returned %s smpp_status error.', args[0]['smpp_status']) raise DeliverSmInterceptionError( code=args[0]['smpp_status']) elif isinstance(args[0], str): smpp.factory.stats.inc('interceptor_count') routable = pickle.loads(args[0]) else: smpp.factory.stats.inc('interceptor_error_count') self.log.error( 'Failed running interception script, got the following return: %s', args[0]) raise InterceptorRunError( 'Failed running interception script, got the following return: %s' % args[0]) self.log.debug( 'Handling deliver_sm_event_post_interception event for smppc: %s', self.SMPPClientFactory.config.id) routable.pdu.dlr = self.SMPPOperationFactory.isDeliveryReceipt( routable.pdu) content = DeliverSmContent(routable, self.SMPPClientFactory.config.id, pickleProtocol=self.pickleProtocol, concatenated=concatenated) msgid = content.properties['message-id'] if routable.pdu.dlr is None: # We have a SMS-MO # UDH is set ? UDHI_INDICATOR_SET = False if 'esm_class' in routable.pdu.params and hasattr( routable.pdu.params['esm_class'], 'gsmFeatures'): for gsmFeature in routable.pdu.params[ 'esm_class'].gsmFeatures: if str(gsmFeature) == 'UDHI_INDICATOR_SET': UDHI_INDICATOR_SET = True break not_class2 = True if 'data_coding' in routable.pdu.params: dcs = routable.pdu.params['data_coding'] if (str(dcs.scheme) == 'GSM_MESSAGE_CLASS') and (dcs.schemeData is not None): not_class2 = (str(dcs.schemeData.msgClass) != 'CLASS_2') splitMethod = None # Is it a part of a long message ? if 'sar_msg_ref_num' in routable.pdu.params: splitMethod = 'sar' total_segments = routable.pdu.params['sar_total_segments'] segment_seqnum = routable.pdu.params['sar_segment_seqnum'] msg_ref_num = routable.pdu.params['sar_msg_ref_num'] self.log.debug( 'Received SMS-MO part [queue-msgid:%s] using SAR: ttl_segments=%s, segment_sn=%s, msgref=%s', msgid, total_segments, segment_seqnum, msg_ref_num) elif UDHI_INDICATOR_SET and not_class2 and message_content[: 3] == '\x05\x00\x03': splitMethod = 'udh' total_segments = struct.unpack('!B', message_content[4])[0] segment_seqnum = struct.unpack('!B', message_content[5])[0] msg_ref_num = struct.unpack('!B', message_content[3])[0] self.log.debug( 'Received SMS-MO part [queue-msgid:%s] using UDH: ttl_segments=%s, segment_sn=%s, msgref=%s', msgid, total_segments, segment_seqnum, msg_ref_num) if splitMethod is None: # It's a simple short message or a part of a concatenated message routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug( "Publishing DeliverSmContent[%s] with routing_key[%s]", msgid, routing_key) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) # Get values from data_sm or deliver_sm priority_flag = None if 'priority_flag' in routable.pdu.params: priority_flag = routable.pdu.params['priority_flag'] validity_period = None if 'validity_period' in routable.pdu.params: validity_period = routable.pdu.params[ 'validity_period'] # Do not log text for privacy reasons # Added in #691 if self.config.log_privacy: logged_content = '** %s byte content **' % len( message_content) else: logged_content = '%r' % message_content self.log.info( "SMS-MO [cid:%s] [queue-msgid:%s] [status:%s] [prio:%s] [validity:%s] [from:%s] [to:%s] \ [content:%s]", self.SMPPClientFactory.config.id, msgid, routable.pdu.status, priority_flag, validity_period, routable.pdu.params['source_addr'], routable.pdu.params['destination_addr'], logged_content) else: # Long message part received if self.redisClient is None: self.log.critical( 'Invalid RC found while receiving part of long DeliverSm [queue-msgid:%s], MSG IS LOST !', msgid) else: # Save it to redis hashKey = "longDeliverSm:%s:%s:%s" % ( self.SMPPClientFactory.config.id, msg_ref_num, routable.pdu.params['destination_addr']) hashValues = { 'pdu': routable.pdu, 'total_segments': total_segments, 'msg_ref_num': msg_ref_num, 'segment_seqnum': segment_seqnum } yield self.redisClient.hset( hashKey, segment_seqnum, pickle.dumps(hashValues, self.pickleProtocol)).addCallback( self.concatDeliverSMs, hashKey, splitMethod, total_segments, msg_ref_num, segment_seqnum) self.log.info( "DeliverSmContent[%s] is part of long msg of (%s), will be enqueued after concatenation.", msgid, total_segments) # Flag it as "will_be_concatenated" and publish it to router routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug( "Publishing DeliverSmContent[%s](flagged:wbc) with routing_key[%s]", msgid, routing_key) content.properties['headers'][ 'will_be_concatenated'] = True yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) else: # This is a DLR ! # Send DLR to DLRLookup yield self.amqpBroker.publish( exchange='messaging', routing_key='dlr.deliver_sm', content=DLR(pdu_type=routable.pdu.id, msgid=self.code_dlr_msgid(routable.pdu), status=routable.pdu.dlr['stat'], cid=self.SMPPClientFactory.config.id, dlr_details=routable.pdu.dlr)) except (InterceptorRunError, DeliverSmInterceptionError) as e: # Do not log text for privacy reasons # Added in #691 if self.config.log_privacy: logged_content = '** %s byte content **' % len(message_content) else: logged_content = '%r' % message_content self.log.info( "SMS-MO [cid:%s] [i-status:%s] [from:%s] [to:%s] [content:%s]", self.SMPPClientFactory.config.id, e.status, routable.pdu.params['source_addr'], routable.pdu.params['destination_addr'], logged_content) # Known exception handling defer.returnValue(DataHandlerResponse(status=e.status)) except Exception as e: # Unknown exception handling self.log.critical('Got an unknown exception (%s): %s', type(e), e) defer.returnValue( DataHandlerResponse(status=CommandStatus.ESME_RUNKNOWNERR))
def deliver_sm_event_post_interception(self, *args, **kw): """This event is called whenever a deliver_sm pdu is received through a SMPPc It will hand the pdu to the router or a dlr thrower (depending if its a DLR or not). Note: this event will catch data_sm pdus as well """ try: # Control args if 'smpp' not in kw or 'pdu' not in kw: self.log.error( 'deliver_sm_event_post_interception missing arguments after interception: %s', kw) raise InterceptorRunError( 'deliver_sm_event_post_interception missing arguments after interception') # Set defaults smpp = kw['smpp'] pdu = kw['pdu'] if 'concatenated' in kw: concatenated = kw['concatenated'] else: concatenated = False # Post interception: if len(args) == 1: if isinstance(args[0], bool) and args[0] == False: smpp.factory.stats.inc('interceptor_error_count') self.log.error('Failed running interception script, got a False return.') raise InterceptorRunError('Failed running interception script, check log for details') elif isinstance(args[0], dict) and args[0]['smpp_status'] > 0: smpp.factory.stats.inc('interceptor_error_count') self.log.info( 'Interceptor script returned %s smpp_status error.', args[0]['smpp_status']) raise DeliverSmInterceptionError(code=args[0]['smpp_status']) elif isinstance(args[0], str): smpp.factory.stats.inc('interceptor_count') temp_routable = pickle.loads(args[0]) pdu = temp_routable.pdu else: smpp.factory.stats.inc('interceptor_error_count') self.log.error( 'Failed running interception script, got the following return: %s', args[0]) raise InterceptorRunError( 'Failed running interception script, got the following return: %s', args[0]) self.log.debug('Handling deliver_sm_event_post_interception event for smppc: %s', self.SMPPClientFactory.config.id) pdu.dlr = self.SMPPOperationFactory.isDeliveryReceipt(pdu) content = DeliverSmContent(pdu, self.SMPPClientFactory.config.id, pickleProtocol=self.pickleProtocol, concatenated=concatenated) msgid = content.properties['message-id'] if pdu.dlr is None: # We have a SMS-MO # UDH is set ? UDHI_INDICATOR_SET = False if hasattr(pdu.params['esm_class'], 'gsmFeatures'): for gsmFeature in pdu.params['esm_class'].gsmFeatures: if str(gsmFeature) == 'UDHI_INDICATOR_SET': UDHI_INDICATOR_SET = True break splitMethod = None # Is it a part of a long message ? if 'sar_msg_ref_num' in pdu.params: splitMethod = 'sar' total_segments = pdu.params['sar_total_segments'] segment_seqnum = pdu.params['sar_segment_seqnum'] msg_ref_num = pdu.params['sar_msg_ref_num'] self.log.debug('Received a part of SMS-MO [queue-msgid:%s] using SAR options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s', msgid, total_segments, segment_seqnum, msg_ref_num) elif UDHI_INDICATOR_SET and pdu.params['short_message'][:3] == '\x05\x00\x03': splitMethod = 'udh' total_segments = struct.unpack('!B', pdu.params['short_message'][4])[0] segment_seqnum = struct.unpack('!B', pdu.params['short_message'][5])[0] msg_ref_num = struct.unpack('!B', pdu.params['short_message'][3])[0] self.log.debug('Received a part of SMS-MO [queue-msgid:%s] using UDH options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s', msgid, total_segments, segment_seqnum, msg_ref_num) if splitMethod is None: # It's a simple short message or a part of a concatenated message routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s] with routing_key[%s]", msgid, routing_key) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) self.log.info("SMS-MO [cid:%s] [queue-msgid:%s] [status:%s] [prio:%s] [validity:%s] [from:%s] [to:%s] [content:%s]", self.SMPPClientFactory.config.id, msgid, pdu.status, pdu.params['priority_flag'], pdu.params['validity_period'], pdu.params['source_addr'], pdu.params['destination_addr'], re.sub(r'[^\x20-\x7E]+', '.', pdu.params['short_message'])) else: # Long message part received if self.redisClient is None: self.warn('No valid RC were found while receiving a part of a long DeliverSm [queue-msgid:%s], MESSAGE IS LOST !', msgid) # Save it to redis hashKey = "longDeliverSm:%s" % (msg_ref_num) hashValues = {'pdu': pdu, 'total_segments':total_segments, 'msg_ref_num':msg_ref_num, 'segment_seqnum':segment_seqnum} self.redisClient.hset( hashKey, segment_seqnum, pickle.dumps(hashValues, self.pickleProtocol)).addCallback( self.concatDeliverSMs, splitMethod, total_segments, msg_ref_num, segment_seqnum) self.log.info("DeliverSmContent[%s] is a part of a long message of %s parts, will be sent to queue after concatenation.", msgid, total_segments) # Flag it as "will_be_concatenated" and publish it to router routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s](flagged:wbc) with routing_key[%s]", msgid, routing_key) content.properties['headers']['will_be_concatenated'] = True yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) else: # This is a DLR ! # Check for DLR request if self.redisClient is not None: _coded_dlr_id = self.code_dlr_msgid(pdu) q = yield self.redisClient.get("queue-msgid:%s" % _coded_dlr_id) submit_sm_queue_id = None connector_type = None if q is not None: q = pickle.loads(q) submit_sm_queue_id = q['msgid'] connector_type = q['connector_type'] if submit_sm_queue_id is not None and connector_type == 'httpapi': pickledDlr = yield self.redisClient.get("dlr:%s" % submit_sm_queue_id) if pickledDlr is not None: dlr = pickle.loads(pickledDlr) dlr_url = dlr['url'] dlr_level = dlr['level'] dlr_method = dlr['method'] if dlr_level in [2, 3]: self.log.debug('Got DLR information for msgid[%s], url:%s, level:%s', submit_sm_queue_id, dlr_url, dlr_level) # The dlr_url in DLRContentForHttpapi indicates the level # of the actual delivery receipt (2) and not the # requested one (maybe 2 or 3) content = DLRContentForHttpapi(pdu.dlr['stat'], submit_sm_queue_id, dlr_url, dlr_level=2, id_smsc=_coded_dlr_id, sub=pdu.dlr['sub'], dlvrd=pdu.dlr['dlvrd'], subdate=pdu.dlr['sdate'], donedate=pdu.dlr['ddate'], err=pdu.dlr['err'], text=pdu.dlr['text'], method=dlr_method) routing_key = 'dlr_thrower.http' self.log.debug("Publishing DLRContentForHttpapi[%s] with routing_key[%s]", submit_sm_queue_id, routing_key) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) self.log.debug('Removing DLR request for msgid[%s]', submit_sm_queue_id) yield self.redisClient.delete('dlr:%s' % submit_sm_queue_id) else: self.log.debug('SMS-C receipt is requested, will not send any DLR receipt at this level.') else: self.log.warn('DLR for msgid[%s] not found !', submit_sm_queue_id) elif submit_sm_queue_id is not None and connector_type == 'smpps': pickledSmppsMap = yield self.redisClient.get("smppsmap:%s" % submit_sm_queue_id) if pickledSmppsMap is not None: smpps_map = pickle.loads(pickledSmppsMap) system_id = smpps_map['system_id'] source_addr = smpps_map['source_addr'] destination_addr = smpps_map['destination_addr'] sub_date = smpps_map['sub_date'] registered_delivery = smpps_map['registered_delivery'] success_states = ['ACCEPTD', 'DELIVRD'] final_states = ['DELIVRD', 'EXPIRED', 'DELETED', 'UNDELIV', 'REJECTD'] # Do we need to forward the receipt to the original sender ? if ((pdu.dlr['stat'] in success_states and str(registered_delivery.receipt) == 'SMSC_DELIVERY_RECEIPT_REQUESTED') or (pdu.dlr['stat'] not in success_states and str(registered_delivery.receipt) in ['SMSC_DELIVERY_RECEIPT_REQUESTED', 'SMSC_DELIVERY_RECEIPT_REQUESTED_FOR_FAILURE'])): self.log.debug( 'Got DLR information for msgid[%s], registered_deliver%s, system_id:%s', submit_sm_queue_id, registered_delivery, system_id) content = DLRContentForSmpps(pdu.dlr['stat'], submit_sm_queue_id, system_id, source_addr, destination_addr, sub_date) routing_key = 'dlr_thrower.smpps' self.log.debug("Publishing DLRContentForSmpps[%s] with routing_key[%s]", submit_sm_queue_id, routing_key) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) if pdu.dlr['stat'] in final_states: self.log.debug('Removing SMPPs map for msgid[%s]', submit_sm_queue_id) yield self.redisClient.delete('smppsmap:%s' % submit_sm_queue_id) else: self.log.warn('Got a DLR for an unknown message id: %s (coded:%s)', pdu.dlr['id'], _coded_dlr_id) else: self.log.warn('DLR for msgid[%s] is not checked, no valid RC were found', msgid) self.log.info("DLR [cid:%s] [smpp-msgid:%s] [status:%s] [submit date:%s] [done date:%s] [sub/dlvrd messages:%s/%s] [err:%s] [content:%s]", self.SMPPClientFactory.config.id, _coded_dlr_id, pdu.dlr['stat'], pdu.dlr['sdate'], pdu.dlr['ddate'], pdu.dlr['sub'], pdu.dlr['dlvrd'], pdu.dlr['err'], pdu.dlr['text']) except (InterceptorRunError, DeliverSmInterceptionError) as e: self.log.info("SMS-MO [cid:%s] [istatus:%s] [from:%s] [to:%s] [content:%s]", self.SMPPClientFactory.config.id, e.status, pdu.params['source_addr'], pdu.params['destination_addr'], re.sub(r'[^\x20-\x7E]+', '.', pdu.params['short_message'])) # Known exception handling defer.returnValue(DataHandlerResponse(status=e.status)) except Exception, e: # Unknown exception handling self.log.critical('Got an unknown exception: %s', e) defer.returnValue(DataHandlerResponse(status=CommandStatus.ESME_RUNKNOWNERR))
def deliver_sm_event_post_interception(self, *args, **kw): """This event is called whenever a deliver_sm pdu is received through a SMPPc It will hand the pdu to the router or a dlr thrower (depending if its a DLR or not). Note: this event will catch data_sm pdus as well """ try: # Control args if 'smpp' not in kw or 'pdu' not in kw: self.log.error( 'deliver_sm_event_post_interception missing arguments after interception: %s', kw) raise InterceptorRunError( 'deliver_sm_event_post_interception missing arguments after interception') # Set defaults smpp = kw['smpp'] pdu = kw['pdu'] if 'concatenated' in kw: concatenated = kw['concatenated'] else: concatenated = False # Get message_content if 'short_message' in pdu.params: message_content = pdu.params['short_message'] elif 'message_payload' in pdu.params: message_content = pdu.params['message_payload'] else: message_content = None # Post interception: if len(args) == 1: if isinstance(args[0], bool) and not args[0]: smpp.factory.stats.inc('interceptor_error_count') self.log.error('Failed running interception script, got a False return.') raise InterceptorRunError('Failed running interception script, check log for details') elif isinstance(args[0], dict) and args[0]['smpp_status'] > 0: smpp.factory.stats.inc('interceptor_error_count') self.log.info( 'Interceptor script returned %s smpp_status error.', args[0]['smpp_status']) raise DeliverSmInterceptionError(code=args[0]['smpp_status']) elif isinstance(args[0], str): smpp.factory.stats.inc('interceptor_count') temp_routable = pickle.loads(args[0]) pdu = temp_routable.pdu else: smpp.factory.stats.inc('interceptor_error_count') self.log.error( 'Failed running interception script, got the following return: %s', args[0]) raise InterceptorRunError( 'Failed running interception script, got the following return: %s', args[0]) self.log.debug('Handling deliver_sm_event_post_interception event for smppc: %s', self.SMPPClientFactory.config.id) pdu.dlr = self.SMPPOperationFactory.isDeliveryReceipt(pdu) content = DeliverSmContent(pdu, self.SMPPClientFactory.config.id, pickleProtocol=self.pickleProtocol, concatenated=concatenated) msgid = content.properties['message-id'] if pdu.dlr is None: # We have a SMS-MO # UDH is set ? UDHI_INDICATOR_SET = False if 'esm_class' in pdu.params and hasattr(pdu.params['esm_class'], 'gsmFeatures'): for gsmFeature in pdu.params['esm_class'].gsmFeatures: if str(gsmFeature) == 'UDHI_INDICATOR_SET': UDHI_INDICATOR_SET = True break splitMethod = None # Is it a part of a long message ? if 'sar_msg_ref_num' in pdu.params: splitMethod = 'sar' total_segments = pdu.params['sar_total_segments'] segment_seqnum = pdu.params['sar_segment_seqnum'] msg_ref_num = pdu.params['sar_msg_ref_num'] self.log.debug('Received a part of SMS-MO [queue-msgid:%s] using SAR options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s', msgid, total_segments, segment_seqnum, msg_ref_num) elif UDHI_INDICATOR_SET and message_content[:3] == '\x05\x00\x03': splitMethod = 'udh' total_segments = struct.unpack('!B', message_content[4])[0] segment_seqnum = struct.unpack('!B', message_content[5])[0] msg_ref_num = struct.unpack('!B', message_content[3])[0] self.log.debug('Received a part of SMS-MO [queue-msgid:%s] using UDH options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s', msgid, total_segments, segment_seqnum, msg_ref_num) if splitMethod is None: # It's a simple short message or a part of a concatenated message routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s] with routing_key[%s]", msgid, routing_key) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) # Get values from data_sm or deliver_sm priority_flag = None if 'priority_flag' in pdu.params: priority_flag = pdu.params['priority_flag'] validity_period = None if 'validity_period' in pdu.params: validity_period = pdu.params['validity_period'] self.log.info("SMS-MO [cid:%s] [queue-msgid:%s] [status:%s] [prio:%s] [validity:%s] [from:%s] [to:%s] [content:%s]", self.SMPPClientFactory.config.id, msgid, pdu.status, priority_flag, validity_period, pdu.params['source_addr'], pdu.params['destination_addr'], re.sub(r'[^\x20-\x7E]+', '.', message_content)) else: # Long message part received if self.redisClient is None: self.warn('No valid RC were found while receiving a part of a long DeliverSm [queue-msgid:%s], MESSAGE IS LOST !', msgid) # Save it to redis hashKey = "longDeliverSm:%s" % (msg_ref_num) hashValues = {'pdu': pdu, 'total_segments':total_segments, 'msg_ref_num':msg_ref_num, 'segment_seqnum':segment_seqnum} yield self.redisClient.hset( hashKey, segment_seqnum, pickle.dumps(hashValues, self.pickleProtocol)).addCallback( self.concatDeliverSMs, splitMethod, total_segments, msg_ref_num, segment_seqnum) self.log.info("DeliverSmContent[%s] is a part of a long message of %s parts, will be sent to queue after concatenation.", msgid, total_segments) # Flag it as "will_be_concatenated" and publish it to router routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s](flagged:wbc) with routing_key[%s]", msgid, routing_key) content.properties['headers']['will_be_concatenated'] = True yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) else: # This is a DLR ! # Check for DLR request if self.redisClient is not None: _coded_dlr_id = self.code_dlr_msgid(pdu) q = yield self.redisClient.get("queue-msgid:%s" % _coded_dlr_id) submit_sm_queue_id = None connector_type = None if q is not None: q = pickle.loads(q) submit_sm_queue_id = q['msgid'] connector_type = q['connector_type'] if submit_sm_queue_id is not None and connector_type == 'httpapi': pickledDlr = yield self.redisClient.get("dlr:%s" % submit_sm_queue_id) if pickledDlr is not None: dlr = pickle.loads(pickledDlr) dlr_url = dlr['url'] dlr_level = dlr['level'] dlr_method = dlr['method'] if dlr_level in [2, 3]: self.log.debug('Got DLR information for msgid[%s], url:%s, level:%s', submit_sm_queue_id, dlr_url, dlr_level) # The dlr_url in DLRContentForHttpapi indicates the level # of the actual delivery receipt (2) and not the # requested one (maybe 2 or 3) content = DLRContentForHttpapi(pdu.dlr['stat'], submit_sm_queue_id, dlr_url, dlr_level=2, id_smsc=_coded_dlr_id, sub=pdu.dlr['sub'], dlvrd=pdu.dlr['dlvrd'], subdate=pdu.dlr['sdate'], donedate=pdu.dlr['ddate'], err=pdu.dlr['err'], text=pdu.dlr['text'], method=dlr_method) routing_key = 'dlr_thrower.http' self.log.debug("Publishing DLRContentForHttpapi[%s] with routing_key[%s]", submit_sm_queue_id, routing_key) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) self.log.debug('Removing DLR request for msgid[%s]', submit_sm_queue_id) yield self.redisClient.delete('dlr:%s' % submit_sm_queue_id) else: self.log.debug('SMS-C receipt is requested, will not send any DLR receipt at this level.') else: self.log.warn('DLR for msgid[%s] not found !', submit_sm_queue_id) elif submit_sm_queue_id is not None and connector_type == 'smpps': pickledSmppsMap = yield self.redisClient.get("smppsmap:%s" % submit_sm_queue_id) if pickledSmppsMap is not None: smpps_map = pickle.loads(pickledSmppsMap) system_id = smpps_map['system_id'] source_addr = smpps_map['source_addr'] destination_addr = smpps_map['destination_addr'] sub_date = smpps_map['sub_date'] registered_delivery = smpps_map['registered_delivery'] success_states = ['ACCEPTD', 'DELIVRD'] final_states = ['DELIVRD', 'EXPIRED', 'DELETED', 'UNDELIV', 'REJECTD'] # Do we need to forward the receipt to the original sender ? if ((pdu.dlr['stat'] in success_states and str(registered_delivery.receipt) == 'SMSC_DELIVERY_RECEIPT_REQUESTED') or (pdu.dlr['stat'] not in success_states and str(registered_delivery.receipt) in ['SMSC_DELIVERY_RECEIPT_REQUESTED', 'SMSC_DELIVERY_RECEIPT_REQUESTED_FOR_FAILURE'])): self.log.debug( 'Got DLR information for msgid[%s], registered_deliver%s, system_id:%s', submit_sm_queue_id, registered_delivery, system_id) content = DLRContentForSmpps(pdu.dlr['stat'], submit_sm_queue_id, system_id, source_addr, destination_addr, sub_date) routing_key = 'dlr_thrower.smpps' self.log.debug("Publishing DLRContentForSmpps[%s] with routing_key[%s]", submit_sm_queue_id, routing_key) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) if pdu.dlr['stat'] in final_states: self.log.debug('Removing SMPPs map for msgid[%s]', submit_sm_queue_id) yield self.redisClient.delete('smppsmap:%s' % submit_sm_queue_id) else: self.log.warn('Got a DLR for an unknown message id: %s (coded:%s)', pdu.dlr['id'], _coded_dlr_id) else: self.log.warn('DLR for msgid[%s] is not checked, no valid RC were found', msgid) self.log.info("DLR [cid:%s] [smpp-msgid:%s] [status:%s] [submit date:%s] [done date:%s] [sub/dlvrd messages:%s/%s] [err:%s] [content:%s]", self.SMPPClientFactory.config.id, _coded_dlr_id, pdu.dlr['stat'], pdu.dlr['sdate'], pdu.dlr['ddate'], pdu.dlr['sub'], pdu.dlr['dlvrd'], pdu.dlr['err'], pdu.dlr['text']) except (InterceptorRunError, DeliverSmInterceptionError) as e: self.log.info("SMS-MO [cid:%s] [istatus:%s] [from:%s] [to:%s] [content:%s]", self.SMPPClientFactory.config.id, e.status, pdu.params['source_addr'], pdu.params['destination_addr'], re.sub(r'[^\x20-\x7E]+', '.', message_content)) # Known exception handling defer.returnValue(DataHandlerResponse(status=e.status)) except Exception, e: # Unknown exception handling self.log.critical('Got an unknown exception: %s', e) defer.returnValue(DataHandlerResponse(status=CommandStatus.ESME_RUNKNOWNERR))
def deliver_sm_event(self, smpp, pdu, concatenated = False): """This event is called whenever a deliver_sm pdu is received through a SMPPc It will hand the pdu to the router or a dlr thrower (depending if its a DLR or not). """ pdu.dlr = self.SMPPOperationFactory.isDeliveryReceipt(pdu) content = DeliverSmContent(pdu, self.SMPPClientFactory.config.id, pickleProtocol = self.pickleProtocol, concatenated = concatenated) msgid = content.properties['message-id'] if pdu.dlr is None: # We have a SMS-MO # UDH is set ? UDHI_INDICATOR_SET = False if hasattr(pdu.params['esm_class'], 'gsmFeatures'): for gsmFeature in pdu.params['esm_class'].gsmFeatures: if str(gsmFeature) == 'UDHI_INDICATOR_SET': UDHI_INDICATOR_SET = True break splitMethod = None # Is it a part of a long message ? if 'sar_msg_ref_num' in pdu.params: splitMethod = 'sar' total_segments = pdu.params['sar_total_segments'] segment_seqnum = pdu.params['sar_segment_seqnum'] msg_ref_num = pdu.params['sar_msg_ref_num'] self.log.debug('Received a part of SMS-MO [queue-msgid:%s] using SAR options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s' % (msgid, total_segments, segment_seqnum, msg_ref_num)) elif UDHI_INDICATOR_SET and pdu.params['short_message'][:3] == '\x05\x00\x03': splitMethod = 'udh' total_segments = struct.unpack('!B', pdu.params['short_message'][4])[0] segment_seqnum = struct.unpack('!B', pdu.params['short_message'][5])[0] msg_ref_num = struct.unpack('!B', pdu.params['short_message'][3])[0] self.log.debug('Received a part of SMS-MO [queue-msgid:%s] using UDH options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s' % (msgid, total_segments, segment_seqnum, msg_ref_num)) if splitMethod is None: # It's a simple short message or a part of a concatenated message routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s] with routing_key[%s]" % (msgid, routing_key)) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) self.log.info("SMS-MO [cid:%s] [queue-msgid:%s] [status:%s] [prio:%s] [validity:%s] [from:%s] [to:%s] [content:%s]" % ( self.SMPPClientFactory.config.id, msgid, pdu.status, pdu.params['priority_flag'], pdu.params['validity_period'], pdu.params['source_addr'], pdu.params['destination_addr'], pdu.params['short_message'] )) else: # Long message part received if self.redisClient is None: self.warn('No valid RC were found while receiving a part of a long DeliverSm [queue-msgid:%s], MESSAGE IS LOST !' % msgid) # Save it to redis hashKey = "longDeliverSm:%s" % (msg_ref_num) hashValues = {'pdu': pdu, 'total_segments':total_segments, 'msg_ref_num':msg_ref_num, 'segment_seqnum':segment_seqnum} self.redisClient.hset(hashKey, segment_seqnum, pickle.dumps(hashValues, self.pickleProtocol ) ).addCallback(self.concatDeliverSMs, splitMethod, total_segments, msg_ref_num, segment_seqnum) self.log.info("DeliverSmContent[%s] is a part of a long message of %s parts, will be sent to queue after concatenation." % (msgid, total_segments)) # Flag it as "will_be_concatenated" and publish it to router routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s](flagged:wbc) with routing_key[%s]" % (msgid, routing_key)) content.properties['headers']['will_be_concatenated'] = True yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) else: # This is a DLR ! # Check for DLR request if self.redisClient is not None: q = yield self.redisClient.get("queue-msgid:%s" % pdu.dlr['id']) submit_sm_queue_id = None connector_type = None if q is not None: q = pickle.loads(q) submit_sm_queue_id = q['msgid'] connector_type = q['connector_type'] if submit_sm_queue_id is not None and connector_type == 'httpapi': pickledDlr = yield self.redisClient.get("dlr:%s" % submit_sm_queue_id) if pickledDlr is not None: dlr = pickle.loads(pickledDlr) dlr_url = dlr['url'] dlr_level = dlr['level'] dlr_method = dlr['method'] if dlr_level in [2, 3]: self.log.debug('Got DLR information for msgid[%s], url:%s, level:%s' % (submit_sm_queue_id, dlr_url, dlr_level)) content = DLRContentForHttpapi(pdu.dlr['stat'], submit_sm_queue_id, dlr_url, # The dlr_url in DLRContentForHttpapi indicates the level # of the actual delivery receipt (2) and not the # requested one (maybe 2 or 3) dlr_level = 2, id_smsc = pdu.dlr['id'], sub = pdu.dlr['sub'], dlvrd = pdu.dlr['dlvrd'], subdate = pdu.dlr['sdate'], donedate = pdu.dlr['ddate'], err = pdu.dlr['err'], text = pdu.dlr['text'], method = dlr_method) routing_key = 'dlr_thrower.http' self.log.debug("Publishing DLRContentForHttpapi[%s] with routing_key[%s]" % (submit_sm_queue_id, routing_key)) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) self.log.debug('Removing DLR request for msgid[%s]' % submit_sm_queue_id) yield self.redisClient.delete('dlr:%s' % submit_sm_queue_id) else: self.log.debug('SMS-C receipt is requested, will not send any DLR receipt at this level.') else: self.log.warn('Got invalid DLR information for msgid[%s], url:%s, level:%s' % (submit_sm_queue_id, dlr_url, dlr_level)) elif submit_sm_queue_id is not None and connector_type == 'smpps': pickledSmppsMap = yield self.redisClient.get("smppsmap:%s" % submit_sm_queue_id) if pickledSmppsMap is not None: smpps_map = pickle.loads(pickledSmppsMap) system_id = smpps_map['system_id'] source_addr = smpps_map['source_addr'] destination_addr = smpps_map['destination_addr'] registered_delivery = smpps_map['registered_delivery'] smpps_map_expiry = smpps_map['expiry'] success_states = ['ACCEPTD', 'DELIVRD'] final_states = ['DELIVRD', 'EXPIRED', 'DELETED', 'UNDELIV', 'REJECTD'] # Do we need to forward the receipt to the original sender ? if ((pdu.dlr['stat'] in success_states and str(registered_delivery.receipt) in ['SMSC_DELIVERY_RECEIPT_REQUESTED', 'SMSC_DELIVERY_RECEIPT_REQUESTED_FOR_FAILURE']) or (pdu.dlr['stat'] not in success_states and str(registered_delivery.receipt) == 'SMSC_DELIVERY_RECEIPT_REQUESTED_FOR_FAILURE')): self.log.debug('Got DLR information for msgid[%s], registered_deliver%s, system_id:%s' % (submit_sm_queue_id, registered_delivery, system_id)) content = DLRContentForSmpps(pdu.dlr['stat'], submit_sm_queue_id, system_id, source_addr, destination_addr) routing_key = 'dlr_thrower.smpps' self.log.debug("Publishing DLRContentForSmpps[%s] with routing_key[%s]" % (submit_sm_queue_id, routing_key)) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) if pdu.dlr['stat'] in final_states: self.log.debug('Removing SMPPs map for msgid[%s]' % submit_sm_queue_id) yield self.redisClient.delete('smppsmap:%s' % submit_sm_queue_id) else: self.log.warn('Got a DLR for an unknown message id: %s' % pdu.dlr['id']) else: self.log.warn('DLR for msgid[%s] is not checked, no valid RC were found' % msgid) self.log.info("DLR [cid:%s] [smpp-msgid:%s] [status:%s] [submit date:%s] [done date:%s] [submitted/delivered messages:%s/%s] [err:%s] [content:%s]" % ( self.SMPPClientFactory.config.id, pdu.dlr['id'], pdu.dlr['stat'], pdu.dlr['sdate'], pdu.dlr['ddate'], pdu.dlr['sub'], pdu.dlr['dlvrd'], pdu.dlr['err'], pdu.dlr['text'], ))
def deliver_sm_event(self, smpp, pdu, concatenated=False): """This event is called whenever a deliver_sm pdu is received through a SMPPc It will hand the pdu to the router or a dlr thrower (depending if its a DLR or not). Note: this event will catch data_sm pdus as well """ pdu.dlr = self.SMPPOperationFactory.isDeliveryReceipt(pdu) content = DeliverSmContent(pdu, self.SMPPClientFactory.config.id, pickleProtocol=self.pickleProtocol, concatenated=concatenated) msgid = content.properties['message-id'] if pdu.dlr is None: # We have a SMS-MO # UDH is set ? UDHI_INDICATOR_SET = False if hasattr(pdu.params['esm_class'], 'gsmFeatures'): for gsmFeature in pdu.params['esm_class'].gsmFeatures: if str(gsmFeature) == 'UDHI_INDICATOR_SET': UDHI_INDICATOR_SET = True break splitMethod = None # Is it a part of a long message ? if 'sar_msg_ref_num' in pdu.params: splitMethod = 'sar' total_segments = pdu.params['sar_total_segments'] segment_seqnum = pdu.params['sar_segment_seqnum'] msg_ref_num = pdu.params['sar_msg_ref_num'] self.log.debug( 'Received a part of SMS-MO [queue-msgid:%s] using SAR options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s' % (msgid, total_segments, segment_seqnum, msg_ref_num)) elif UDHI_INDICATOR_SET and pdu.params[ 'short_message'][:3] == '\x05\x00\x03': splitMethod = 'udh' total_segments = struct.unpack( '!B', pdu.params['short_message'][4])[0] segment_seqnum = struct.unpack( '!B', pdu.params['short_message'][5])[0] msg_ref_num = struct.unpack('!B', pdu.params['short_message'][3])[0] self.log.debug( 'Received a part of SMS-MO [queue-msgid:%s] using UDH options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s' % (msgid, total_segments, segment_seqnum, msg_ref_num)) if splitMethod is None: # It's a simple short message or a part of a concatenated message routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug( "Publishing DeliverSmContent[%s] with routing_key[%s]" % (msgid, routing_key)) yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) self.log.info( "SMS-MO [cid:%s] [queue-msgid:%s] [status:%s] [prio:%s] [validity:%s] [from:%s] [to:%s] [content:%s]" % (self.SMPPClientFactory.config.id, msgid, pdu.status, pdu.params['priority_flag'], pdu.params['validity_period'], pdu.params['source_addr'], pdu.params['destination_addr'], re.sub(r'[^\x20-\x7E]+', '.', pdu.params['short_message']))) else: # Long message part received if self.redisClient is None: self.warn( 'No valid RC were found while receiving a part of a long DeliverSm [queue-msgid:%s], MESSAGE IS LOST !' % msgid) # Save it to redis hashKey = "longDeliverSm:%s" % (msg_ref_num) hashValues = { 'pdu': pdu, 'total_segments': total_segments, 'msg_ref_num': msg_ref_num, 'segment_seqnum': segment_seqnum } self.redisClient.hset( hashKey, segment_seqnum, pickle.dumps(hashValues, self.pickleProtocol)).addCallback( self.concatDeliverSMs, splitMethod, total_segments, msg_ref_num, segment_seqnum) self.log.info( "DeliverSmContent[%s] is a part of a long message of %s parts, will be sent to queue after concatenation." % (msgid, total_segments)) # Flag it as "will_be_concatenated" and publish it to router routing_key = 'deliver.sm.%s' % self.SMPPClientFactory.config.id self.log.debug( "Publishing DeliverSmContent[%s](flagged:wbc) with routing_key[%s]" % (msgid, routing_key)) content.properties['headers']['will_be_concatenated'] = True yield self.amqpBroker.publish(exchange='messaging', routing_key=routing_key, content=content) else: # This is a DLR ! # Check for DLR request if self.redisClient is not None: _coded_dlr_id = self.code_dlr_msgid(pdu) q = yield self.redisClient.get("queue-msgid:%s" % _coded_dlr_id) submit_sm_queue_id = None connector_type = None if q is not None: q = pickle.loads(q) submit_sm_queue_id = q['msgid'] connector_type = q['connector_type'] if submit_sm_queue_id is not None and connector_type == 'httpapi': pickledDlr = yield self.redisClient.get("dlr:%s" % submit_sm_queue_id) if pickledDlr is not None: dlr = pickle.loads(pickledDlr) dlr_url = dlr['url'] dlr_level = dlr['level'] dlr_method = dlr['method'] if dlr_level in [2, 3]: self.log.debug( 'Got DLR information for msgid[%s], url:%s, level:%s' % (submit_sm_queue_id, dlr_url, dlr_level)) content = DLRContentForHttpapi( pdu.dlr['stat'], submit_sm_queue_id, dlr_url, # The dlr_url in DLRContentForHttpapi indicates the level # of the actual delivery receipt (2) and not the # requested one (maybe 2 or 3) dlr_level=2, id_smsc=_coded_dlr_id, sub=pdu.dlr['sub'], dlvrd=pdu.dlr['dlvrd'], subdate=pdu.dlr['sdate'], donedate=pdu.dlr['ddate'], err=pdu.dlr['err'], text=pdu.dlr['text'], method=dlr_method) routing_key = 'dlr_thrower.http' self.log.debug( "Publishing DLRContentForHttpapi[%s] with routing_key[%s]" % (submit_sm_queue_id, routing_key)) yield self.amqpBroker.publish( exchange='messaging', routing_key=routing_key, content=content) self.log.debug( 'Removing DLR request for msgid[%s]' % submit_sm_queue_id) yield self.redisClient.delete('dlr:%s' % submit_sm_queue_id) else: self.log.debug( 'SMS-C receipt is requested, will not send any DLR receipt at this level.' ) else: self.log.warn('DLR for msgid[%s] not found !' % (submit_sm_queue_id)) elif submit_sm_queue_id is not None and connector_type == 'smpps': pickledSmppsMap = yield self.redisClient.get( "smppsmap:%s" % submit_sm_queue_id) if pickledSmppsMap is not None: smpps_map = pickle.loads(pickledSmppsMap) system_id = smpps_map['system_id'] source_addr = smpps_map['source_addr'] destination_addr = smpps_map['destination_addr'] sub_date = smpps_map['sub_date'] registered_delivery = smpps_map['registered_delivery'] smpps_map_expiry = smpps_map['expiry'] success_states = ['ACCEPTD', 'DELIVRD'] final_states = [ 'DELIVRD', 'EXPIRED', 'DELETED', 'UNDELIV', 'REJECTD' ] # Do we need to forward the receipt to the original sender ? if ((pdu.dlr['stat'] in success_states and str(registered_delivery.receipt) == 'SMSC_DELIVERY_RECEIPT_REQUESTED') or (pdu.dlr['stat'] not in success_states and str(registered_delivery.receipt) in [ 'SMSC_DELIVERY_RECEIPT_REQUESTED', 'SMSC_DELIVERY_RECEIPT_REQUESTED_FOR_FAILURE' ])): self.log.debug( 'Got DLR information for msgid[%s], registered_deliver%s, system_id:%s' % (submit_sm_queue_id, registered_delivery, system_id)) content = DLRContentForSmpps( pdu.dlr['stat'], submit_sm_queue_id, system_id, source_addr, destination_addr, sub_date) routing_key = 'dlr_thrower.smpps' self.log.debug( "Publishing DLRContentForSmpps[%s] with routing_key[%s]" % (submit_sm_queue_id, routing_key)) yield self.amqpBroker.publish( exchange='messaging', routing_key=routing_key, content=content) if pdu.dlr['stat'] in final_states: self.log.debug( 'Removing SMPPs map for msgid[%s]' % submit_sm_queue_id) yield self.redisClient.delete( 'smppsmap:%s' % submit_sm_queue_id) else: self.log.warn( 'Got a DLR for an unknown message id: %s (coded:%s)' % (pdu.dlr['id'], _coded_dlr_id)) else: self.log.warn( 'DLR for msgid[%s] is not checked, no valid RC were found' % msgid) self.log.info( "DLR [cid:%s] [smpp-msgid:%s] [status:%s] [submit date:%s] [done date:%s] [sub/dlvrd messages:%s/%s] [err:%s] [content:%s]" % ( self.SMPPClientFactory.config.id, _coded_dlr_id, pdu.dlr['stat'], pdu.dlr['sdate'], pdu.dlr['ddate'], pdu.dlr['sub'], pdu.dlr['dlvrd'], pdu.dlr['err'], pdu.dlr['text'], ))
def deliver_sm_event(self, smpp, pdu, concatenated=False): """This event is called whenever a deliver_sm pdu is received through a SMPPc It will hand the pdu to the router or a dlr thrower (depending if its a DLR or not). """ pdu.dlr = self.SMPPOperationFactory.isDeliveryReceipt(pdu) content = DeliverSmContent( pdu, self.SMPPClientFactory.config.id, pickleProtocol=self.pickleProtocol, concatenated=concatenated ) msgid = content.properties["message-id"] if pdu.dlr is None: # We have a SMS-MO # UDH is set ? UDHI_INDICATOR_SET = False if hasattr(pdu.params["esm_class"], "gsmFeatures"): for gsmFeature in pdu.params["esm_class"].gsmFeatures: if str(gsmFeature) == "UDHI_INDICATOR_SET": UDHI_INDICATOR_SET = True break splitMethod = None # Is it a part of a long message ? if "sar_msg_ref_num" in pdu.params: splitMethod = "sar" total_segments = pdu.params["sar_total_segments"] segment_seqnum = pdu.params["sar_segment_seqnum"] msg_ref_num = pdu.params["sar_msg_ref_num"] self.log.debug( "Received a part of SMS-MO [queue-msgid:%s] using SAR options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s" % (msgid, total_segments, segment_seqnum, msg_ref_num) ) elif UDHI_INDICATOR_SET and pdu.params["short_message"][:3] == "\x05\x00\x03": splitMethod = "udh" total_segments = struct.unpack("!B", pdu.params["short_message"][4])[0] segment_seqnum = struct.unpack("!B", pdu.params["short_message"][5])[0] msg_ref_num = struct.unpack("!B", pdu.params["short_message"][3])[0] self.log.debug( "Received a part of SMS-MO [queue-msgid:%s] using UDH options: total_segments=%s, segmen_seqnum=%s, msg_ref_num=%s" % (msgid, total_segments, segment_seqnum, msg_ref_num) ) if splitMethod is None: # It's a simple short message or a part of a concatenated message routing_key = "deliver.sm.%s" % self.SMPPClientFactory.config.id self.log.debug("Publishing DeliverSmContent[%s] with routing_key[%s]" % (msgid, routing_key)) yield self.amqpBroker.publish(exchange="messaging", routing_key=routing_key, content=content) self.log.info( "SMS-MO [cid:%s] [queue-msgid:%s] [status:%s] [prio:%s] [validity:%s] [from:%s] [to:%s] [content:%s]" % ( self.SMPPClientFactory.config.id, msgid, pdu.status, pdu.params["priority_flag"], pdu.params["validity_period"], pdu.params["source_addr"], pdu.params["destination_addr"], pdu.params["short_message"], ) ) else: # Long message part received if self.redisClient is None: self.warn( "No valid RC were found while receiving a part of a long DeliverSm [queue-msgid:%s], MESSAGE IS LOST !" % msgid ) # Save it to redis hashKey = "longDeliverSm:%s" % (msg_ref_num) hashValues = { "pdu": pdu, "total_segments": total_segments, "msg_ref_num": msg_ref_num, "segment_seqnum": segment_seqnum, } self.redisClient.hset( hashKey, segment_seqnum, pickle.dumps(hashValues, self.pickleProtocol) ).addCallback(self.concatDeliverSMs, splitMethod, total_segments, msg_ref_num, segment_seqnum) self.log.info( "DeliverSmContent[%s] is a part of a long message of %s parts, will be sent to queue after concatenation." % (msgid, total_segments) ) # Flag it as "will_be_concatenated" and publish it to router routing_key = "deliver.sm.%s" % self.SMPPClientFactory.config.id self.log.debug( "Publishing DeliverSmContent[%s](flagged:wbc) with routing_key[%s]" % (msgid, routing_key) ) content.properties["headers"]["will_be_concatenated"] = True yield self.amqpBroker.publish(exchange="messaging", routing_key=routing_key, content=content) else: # This is a DLR ! # Check for DLR request if self.redisClient is not None: _coded_dlr_id = self.code_dlr_msgid(pdu) q = yield self.redisClient.get("queue-msgid:%s" % _coded_dlr_id) submit_sm_queue_id = None connector_type = None if q is not None: q = pickle.loads(q) submit_sm_queue_id = q["msgid"] connector_type = q["connector_type"] if submit_sm_queue_id is not None and connector_type == "httpapi": pickledDlr = yield self.redisClient.get("dlr:%s" % submit_sm_queue_id) if pickledDlr is not None: dlr = pickle.loads(pickledDlr) dlr_url = dlr["url"] dlr_level = dlr["level"] dlr_method = dlr["method"] if dlr_level in [2, 3]: self.log.debug( "Got DLR information for msgid[%s], url:%s, level:%s" % (submit_sm_queue_id, dlr_url, dlr_level) ) content = DLRContentForHttpapi( pdu.dlr["stat"], submit_sm_queue_id, dlr_url, # The dlr_url in DLRContentForHttpapi indicates the level # of the actual delivery receipt (2) and not the # requested one (maybe 2 or 3) dlr_level=2, id_smsc=_coded_dlr_id, sub=pdu.dlr["sub"], dlvrd=pdu.dlr["dlvrd"], subdate=pdu.dlr["sdate"], donedate=pdu.dlr["ddate"], err=pdu.dlr["err"], text=pdu.dlr["text"], method=dlr_method, ) routing_key = "dlr_thrower.http" self.log.debug( "Publishing DLRContentForHttpapi[%s] with routing_key[%s]" % (submit_sm_queue_id, routing_key) ) yield self.amqpBroker.publish( exchange="messaging", routing_key=routing_key, content=content ) self.log.debug("Removing DLR request for msgid[%s]" % submit_sm_queue_id) yield self.redisClient.delete("dlr:%s" % submit_sm_queue_id) else: self.log.debug("SMS-C receipt is requested, will not send any DLR receipt at this level.") else: self.log.warn( "Got invalid DLR information for msgid[%s], url:%s, level:%s" % (submit_sm_queue_id, dlr_url, dlr_level) ) elif submit_sm_queue_id is not None and connector_type == "smpps": pickledSmppsMap = yield self.redisClient.get("smppsmap:%s" % submit_sm_queue_id) if pickledSmppsMap is not None: smpps_map = pickle.loads(pickledSmppsMap) system_id = smpps_map["system_id"] source_addr = smpps_map["source_addr"] destination_addr = smpps_map["destination_addr"] sub_date = smpps_map["sub_date"] registered_delivery = smpps_map["registered_delivery"] smpps_map_expiry = smpps_map["expiry"] success_states = ["ACCEPTD", "DELIVRD"] final_states = ["DELIVRD", "EXPIRED", "DELETED", "UNDELIV", "REJECTD"] # Do we need to forward the receipt to the original sender ? if ( pdu.dlr["stat"] in success_states and str(registered_delivery.receipt) == "SMSC_DELIVERY_RECEIPT_REQUESTED" ) or ( pdu.dlr["stat"] not in success_states and str(registered_delivery.receipt) in ["SMSC_DELIVERY_RECEIPT_REQUESTED", "SMSC_DELIVERY_RECEIPT_REQUESTED_FOR_FAILURE"] ): self.log.debug( "Got DLR information for msgid[%s], registered_deliver%s, system_id:%s" % (submit_sm_queue_id, registered_delivery, system_id) ) content = DLRContentForSmpps( pdu.dlr["stat"], submit_sm_queue_id, system_id, source_addr, destination_addr, sub_date ) routing_key = "dlr_thrower.smpps" self.log.debug( "Publishing DLRContentForSmpps[%s] with routing_key[%s]" % (submit_sm_queue_id, routing_key) ) yield self.amqpBroker.publish( exchange="messaging", routing_key=routing_key, content=content ) if pdu.dlr["stat"] in final_states: self.log.debug("Removing SMPPs map for msgid[%s]" % submit_sm_queue_id) yield self.redisClient.delete("smppsmap:%s" % submit_sm_queue_id) else: self.log.warn("Got a DLR for an unknown message id: %s" % pdu.dlr["id"]) else: self.log.warn("DLR for msgid[%s] is not checked, no valid RC were found" % msgid) self.log.info( "DLR [cid:%s] [smpp-msgid:%s] [status:%s] [submit date:%s] [done date:%s] [sub/dlvrd messages:%s/%s] [err:%s] [content:%s]" % ( self.SMPPClientFactory.config.id, _coded_dlr_id, pdu.dlr["stat"], pdu.dlr["sdate"], pdu.dlr["ddate"], pdu.dlr["sub"], pdu.dlr["dlvrd"], pdu.dlr["err"], pdu.dlr["text"], ) )
dest_addr_npi=submit_sm.params['dest_addr_npi'], destination_addr=submit_sm.params['destination_addr'], esm_class=submit_sm.params['esm_class'], protocol_id=submit_sm.params['protocol_id'], priority_flag=submit_sm.params['priority_flag'], registered_delivery=submit_sm.params['registered_delivery'], replace_if_present_flag=submit_sm.params['replace_if_present_flag'], data_coding=submit_sm.params['data_coding'], short_message=submit_sm.params['short_message'], sm_default_msg_id=submit_sm.params['sm_default_msg_id']) logger.debug("Prepared a new deliver_sm: %s", deliver_sm) # Prepare for deliver_sm injection _routable = RoutableDeliverSm(deliver_sm, Connector(routable.user.uid)) content = DeliverSmContent(_routable, routable.user.uid, pickleProtocol=pickle.HIGHEST_PROTOCOL) routing_key = 'deliver.sm.%s' % routable.user.uid # Connecto RabbitMQ and publish deliver_sm logger.debug('Init pika and publish..') connection = pika.BlockingConnection(pika.URLParameters(RABBITMQ_URL)) channel = connection.channel() logger.debug('RabbitMQ channel ready, publishing now msgid %s ...', content.properties['message-id']) channel.basic_publish( 'messaging', routing_key, content.body, pika.BasicProperties(message_id=content.properties['message-id'], headers=content.properties['headers'])) logger.debug('Published deliver_sm to %s', routing_key)