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_pdu(self): """Read PDU from the SMSC""" logger.debug('Waiting for PDU...') try: raw_len = self._socket.recv(4) except socket.timeout: raise except socket.error as e: logger.warning(e) raise exceptions.ConnectionError() if not raw_len: raise exceptions.ConnectionError() try: length = struct.unpack('>L', raw_len)[0] except struct.error: logger.warning('Receive broken pdu... %s', repr(raw_len)) raise exceptions.PDUError('Broken PDU') raw_pdu = self._socket.recv(length - 4) raw_pdu = raw_len + raw_pdu logger.debug('<<%s (%d bytes)', binascii.b2a_hex(raw_pdu), len(raw_pdu)) pdu = smpp.parse_pdu(raw_pdu, client=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 listen(self): """This method implements the actual SMPP server. Note that we can only talk to one client at a time; removing that restriction would make the code much more complicated and we don't really need it. """ msg_count = 0 while True: self._sock.listen() sock, address = self._sock.accept() done = False while not done: # Note how we're leveraging `smpplib` to avoid the – # considerable – inconvenience of parsing (and # generating) SMPP PDUs ourselves. try: pdu = smpp.parse_pdu( self.read_raw_pdu(sock), client=self, allow_unknown_opt_params=None, ) self.pdus.append(pdu) except exceptions.ConnectionError: break # Do something with the PDU. print(f"> {pdu.command}", end="") if pdu.command == "bind_transceiver": status = consts.SMPP_ESME_ROK if self.password is not None: if (pdu.system_id.decode() != self.system_id or pdu.password.decode() != self.password): status = consts.SMPP_ESME_RBINDFAIL res_pdu = smpp.make_pdu( "bind_transceiver_resp", status=status, sequence=pdu._sequence, ) print("\n< OK") elif pdu.command == "submit_sm": text = pdu.short_message.decode() print(f": from={pdu.source_addr.decode()} " f"to={pdu.destination_addr.decode()} " f'text="{text}"') # You can get the server to return any of a bunch # of error codes simply by including the (textual # representation of the) error code in the # message. E.g., send the message `Ahoy SUBMITFAIL # Ahoy` to elicit the error code, # `ESME_RSUBMITFAIL`. data = { "status": pdu.status, "sequence": pdu._sequence, } for err in ( "SYSERR", "MSGQFUL", "SUBMITFAIL", "THROTTLED", "X_T_APPN", "DELIVERYFAILURE", ): if err in text: data["status"] = getattr(consts, "SMPP_ESME_R" + err) out_msg = f"ERR {err}" break else: msg_count += 1 msg_id = f"{MC_ID}:{msg_count:04d}" data["message_id"] = msg_id out_msg = f"OK {msg_id}" self.messages.append(text) res_pdu = smpp.make_pdu("submit_sm_resp", **data) print(f"< {out_msg}") elif pdu.command == "unbind": res_pdu = smpp.make_pdu( "unbind_resp", status=pdu.status, sequence=pdu._sequence, ) done = True print("\n< OK") else: raise ValueError(f"Unsupported SMPP command {pdu.command}") self.pdus.append(res_pdu) response = res_pdu.generate() # self.logger.debug(f'<< {response.hex(" ", -4)}') # Python 3.8 self.logger.debug("<< %s", response.hex()) sock.send(response) sock.close() done = False