def send_pdu(self, p): """Send PDU to the SMSC""" if self.state not in consts.COMMAND_STATES[p.command]: raise exceptions.PDUError("Command %s failed: %s" % ( p.command, consts.DESCRIPTIONS[consts.SMPP_ESME_RINVBNDSTS], )) logger.debug('Sending %s PDU', p.command) generated = p.generate() logger.debug('>>%s (%d bytes)', binascii.b2a_hex(generated), len(generated)) sent = 0 while sent < len(generated): try: sent_last = self._socket.send(generated[sent:]) except socket.error as e: logger.warning(e) raise exceptions.ConnectionError() if sent_last == 0: raise exceptions.ConnectionError() sent += sent_last return True
def error_pdu_handler(self, pdu): raise exceptions.PDUError( '({}) {}: {}'.format( pdu.status, pdu.command, consts.DESCRIPTIONS.get(pdu.status, 'Unknown status')), int(pdu.status), )
def read_pdu(self): """Read PDU from the SMSC""" self.logger.debug('Waiting for PDU...') try: raw_len = self._socket.recv(4) except socket.timeout: raise except socket.error as e: self.logger.warning(e) raise exceptions.ConnectionError() if not raw_len: raise exceptions.ConnectionError() try: length = struct.unpack('>L', raw_len)[0] except struct.error: self.logger.warning('Receive broken pdu... %s', repr(raw_len)) raise exceptions.PDUError('Broken PDU') raw_pdu = raw_len while len(raw_pdu) < length: try: raw_pdu_part = self._socket.recv(length - len(raw_pdu)) except socket.timeout: raise except socket.error as e: self.logger.warning(e) raise exceptions.ConnectionError() if not raw_pdu: raise exceptions.ConnectionError() raw_pdu += raw_pdu_part self.logger.debug('<<%s (%d bytes)', binascii.b2a_hex(raw_pdu), len(raw_pdu)) pdu = smpp.parse_pdu( raw_pdu, client=self, allow_unknown_opt_params=self.allow_unknown_opt_params, ) self.logger.debug('Read %s PDU', pdu.command) if pdu.is_error(): return pdu elif pdu.command in consts.STATE_SETTERS: self.state = consts.STATE_SETTERS[pdu.command] return pdu
def read_once(self, ignore_error_codes=None, auto_send_enquire_link=True): """Read a PDU and act""" try: try: pdu = self.read_pdu() except socket.timeout: if not auto_send_enquire_link: raise self.logger.debug('Socket timeout, listening again') pdu = smpp.make_pdu('enquire_link', client=self) self.send_pdu(pdu) return if pdu.is_error(): raise exceptions.PDUError( '({}) {}: {}'.format( pdu.status, pdu.command, consts.DESCRIPTIONS.get(pdu.status, 'Unknown status')), int(pdu.status), ) if pdu.command == 'unbind': # unbind_res self.logger.info('Unbind command received') return elif pdu.command == 'submit_sm_resp': self.message_sent_handler(pdu=pdu) elif pdu.command == 'deliver_sm': self._message_received(pdu) elif pdu.command == 'query_sm_resp': self.query_resp_handler(pdu) elif pdu.command == 'enquire_link': self._enquire_link_received(pdu) elif pdu.command == 'enquire_link_resp': pass elif pdu.command == 'alert_notification': self._alert_notification(pdu) else: self.logger.warning('Unhandled SMPP command "%s"', pdu.command) except exceptions.PDUError as e: if ignore_error_codes and len( e.args) > 1 and e.args[1] in ignore_error_codes: self.logger.warning('(%d) %s. Ignored.', e.args[1], e.args[0]) else: raise
def _bind(self, command_name, **kwargs): """Send bind_transmitter command to the SMSC""" if command_name in ('bind_receiver', 'bind_transceiver'): logger.debug('Receiver mode') p = smpp.make_pdu(command_name, client=self, **kwargs) self.send_pdu(p) try: resp = self.read_pdu() except socket.timeout: raise exceptions.ConnectionError() if resp.is_error(): raise exceptions.PDUError( '({}) {}: {}'.format( resp.status, resp.command, consts.DESCRIPTIONS.get(resp.status, 'Unknown code')), int(resp.status), ) return resp
def read_raw_pdu(self, sock): """Read a SMPP PDU from the client and return it as a `bytes` object.""" # This part of the code is inspired by^W^Wlargely cribbed from # `smpplib.Client.read_pdu()`. try: pdu_bytes = sock.recv(4) except socket.timeout: raise except socket.error as e: self.logger.warning(e) raise exceptions.ConnectionError() if not pdu_bytes: raise exceptions.ConnectionError() try: length = struct.unpack(">L", pdu_bytes)[0] except struct.error: bad_pdu_msg = "Bad PDU: %r" self.logger.warning(bad_pdu_msg, pdu_bytes) raise exceptions.PDUError(bad_pdu_msg.format(pdu_bytes)) while len(pdu_bytes) < length: try: more_bytes = sock.recv(length - len(pdu_bytes)) except socket.timeout: raise except socket.error as e: self.logger.warning(e) raise exceptions.ConnectionError() if not pdu_bytes: raise exceptions.ConnectionError() pdu_bytes += more_bytes # self.logger.debug(f'>> {pdu_bytes.hex(" ", -4)}') # Python >=3.8 self.logger.debug(">> %s", pdu_bytes.hex()) return pdu_bytes