/* * Telestax, Open Source Cloud Communications Copyright 2011-2017, * Telestax Inc and individual contributors by the @authors tag. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.mobicents.smsc.slee.services.smpp.server.tx; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.sql.Timestamp; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.UUID; import javax.naming.Context; import javax.naming.InitialContext; import javax.slee.ActivityContextInterface; import javax.slee.ActivityEndEvent; import javax.slee.EventContext; import javax.slee.Sbb; import javax.slee.SbbContext; import javax.slee.ServiceID; import javax.slee.serviceactivity.ServiceActivity; import javax.slee.serviceactivity.ServiceStartedEvent; import org.mobicents.protocols.ss7.map.api.errors.MAPErrorCode; import org.mobicents.protocols.ss7.map.api.smstpdu.CharacterSet; import org.mobicents.protocols.ss7.map.api.smstpdu.DataCodingScheme; import org.mobicents.protocols.ss7.map.api.smstpdu.UserDataHeader; import org.mobicents.protocols.ss7.map.datacoding.GSMCharset; import org.mobicents.protocols.ss7.map.datacoding.GSMCharsetDecoder; import org.mobicents.protocols.ss7.map.datacoding.GSMCharsetDecodingData; import org.mobicents.protocols.ss7.map.datacoding.Gsm7EncodingStyle; import org.mobicents.protocols.ss7.map.smstpdu.DataCodingSchemeImpl; import org.mobicents.protocols.ss7.map.smstpdu.UserDataHeaderImpl; import org.mobicents.smsc.cassandra.PersistenceException; import org.mobicents.smsc.domain.SmscCongestionControl; import org.mobicents.smsc.domain.SmscStatAggregator; import org.mobicents.smsc.domain.SmscStatProvider; import org.mobicents.smsc.library.MessageUtil; import org.mobicents.smsc.library.OriginationType; import org.mobicents.smsc.library.SbbStates; import org.mobicents.smsc.library.Sms; import org.mobicents.smsc.library.SmsSet; import org.mobicents.smsc.library.SmscProcessingException; import org.mobicents.smsc.library.TargetAddress; import org.mobicents.smsc.mproc.DeliveryReceiptData; import org.mobicents.smsc.slee.resources.persistence.PersistenceRAInterface; import org.mobicents.smsc.slee.services.submitsbb.SubmitCommonSbb; import org.mobicents.smsc.slee.services.util.SbbStatsUtils; import org.restcomm.slee.resource.smpp.PduRequestTimeout; import org.restcomm.slee.resource.smpp.SmppExtraConstants; import org.restcomm.slee.resource.smpp.SmppSessions; import org.restcomm.slee.resource.smpp.SmppTransaction; import org.restcomm.slee.resource.smpp.SmppTransactionACIFactory; import org.restcomm.smpp.CheckMessageLimitResult; import org.restcomm.smpp.Esme; import org.restcomm.smpp.SmppEncoding; import com.cloudhopper.smpp.SmppConstants; import com.cloudhopper.smpp.pdu.BaseSm; import com.cloudhopper.smpp.pdu.DataSm; import com.cloudhopper.smpp.pdu.DataSmResp; import com.cloudhopper.smpp.pdu.DeliverSmResp; import com.cloudhopper.smpp.pdu.SubmitMulti; import com.cloudhopper.smpp.pdu.SubmitMultiResp; import com.cloudhopper.smpp.pdu.SubmitSm; import com.cloudhopper.smpp.pdu.SubmitSmResp; import com.cloudhopper.smpp.tlv.Tlv; import com.cloudhopper.smpp.tlv.TlvConvertException; import com.cloudhopper.smpp.type.Address; import com.cloudhopper.smpp.type.RecoverablePduException; import com.cloudhopper.smpp.type.SmppInvalidArgumentException; import com.cloudhopper.smpp.type.UnsucessfulSME; import com.cloudhopper.smpp.util.TlvUtil; /** * * @author amit bhayani * @author servey vetyutnev * */ public abstract class TxSmppServerSbb extends SubmitCommonSbb implements Sbb { private static final String className = TxSmppServerSbb.class.getSimpleName(); private static final long ONE = 1L; private SmppTransactionACIFactory smppServerTransactionACIFactory = null; protected SmppSessions smppServerSessions = null; private SmscStatAggregator smscStatAggregator = SmscStatAggregator.getInstance(); private SmscCongestionControl smscCongestionControl = SmscCongestionControl.getInstance(); private static Charset utf8Charset = Charset.forName("UTF-8"); private static Charset ucs2Charset = Charset.forName("UTF-16BE"); private static Charset isoCharset = Charset.forName("ISO-8859-1"); private static Charset gsm7Charset = new GSMCharset("GSM", new String[] {}); public TxSmppServerSbb() { super(className); } // ********* // SBB staff @Override public void setSbbContext(SbbContext sbbContext) { super.setSbbContext(sbbContext); try { Context ctx = (Context) new InitialContext().lookup("java:comp/env"); this.smppServerTransactionACIFactory = (SmppTransactionACIFactory) ctx .lookup("slee/resources/smppp/server/1.0/acifactory"); this.smppServerSessions = (SmppSessions) ctx.lookup("slee/resources/smpp/server/1.0/provider"); } catch (Exception ne) { logger.severe("Could not set SBB context:", ne); } } @Override public void sbbLoad() { super.sbbLoad(); } @Override public void sbbStore() { super.sbbStore(); } /** * Gets the default SBB usage parameter set. * * @return the default SBB usage parameter set */ public abstract TxSmppServerSbbUsage getDefaultSbbUsageParameterSet(); public void onServiceStartedEvent(ServiceStartedEvent event, ActivityContextInterface aci, EventContext eventContext) { ServiceID serviceID = event.getService(); this.logger.info("Rx: onServiceStartedEvent: event=" + event + ", serviceID=" + serviceID); SbbStates.setSmscTxSmppServerServiceState(true); } public void onActivityEndEvent(ActivityEndEvent event, ActivityContextInterface aci, EventContext eventContext) { final TxSmppServerSbbUsage sbbu = getDefaultSbbUsageParameterSet(); sbbu.incrementCounterActivityEnd(ONE); boolean isServiceActivity = (aci.getActivity() instanceof ServiceActivity); if (isServiceActivity) { this.logger.info("Rx: onActivityEndEvent: event=" + event + ", isServiceActivity=" + isServiceActivity); SbbStates.setSmscTxSmppServerServiceState(false); } } // ********* // SMPP Event Handlers public void onSubmitSm(com.cloudhopper.smpp.pdu.SubmitSm event, ActivityContextInterface aci) { final TxSmppServerSbbUsage sbbu = getDefaultSbbUsageParameterSet(); sbbu.incrementCounterSubmitSm(ONE); final long start = System.currentTimeMillis(); onSubmitSmLocal(sbbu, event, aci); sbbu.sampleSubmitSm(System.currentTimeMillis() - start); } public void onDataSm(com.cloudhopper.smpp.pdu.DataSm event, ActivityContextInterface aci) { final TxSmppServerSbbUsage sbbu = getDefaultSbbUsageParameterSet(); sbbu.incrementCounterDataSm(ONE); final long start = System.currentTimeMillis(); onDataSmLocal(sbbu, event, aci); sbbu.sampleDataSm(System.currentTimeMillis() - start); } public void onSubmitMulti(com.cloudhopper.smpp.pdu.SubmitMulti event, ActivityContextInterface aci) { final TxSmppServerSbbUsage sbbu = getDefaultSbbUsageParameterSet(); sbbu.incrementCounterSubmitMultiSm(ONE); final long start = System.currentTimeMillis(); onSubmitMultiLocal(sbbu, event, aci); sbbu.sampleSubmitMultiSm(System.currentTimeMillis() - start); } public void onDeliverSm(com.cloudhopper.smpp.pdu.DeliverSm event, ActivityContextInterface aci) { final TxSmppServerSbbUsage sbbu = getDefaultSbbUsageParameterSet(); sbbu.incrementCounterDeliverSm(ONE); final long start = System.currentTimeMillis(); onDeliverSmLocal(sbbu, event, aci); sbbu.sampleDeliverSm(System.currentTimeMillis() - start); } public void onPduRequestTimeout(PduRequestTimeout event, ActivityContextInterface aci, EventContext eventContext) { final TxSmppServerSbbUsage sbbu = getDefaultSbbUsageParameterSet(); sbbu.incrementCounterErrorPduRequestTimeout(ONE); sbbu.samplePduRequestTimeout(0L); logger.severe(String.format("\nonPduRequestTimeout : PduRequestTimeout=%s", event)); // TODO : Handle this } public void onRecoverablePduException(RecoverablePduException event, ActivityContextInterface aci, EventContext eventContext) { final TxSmppServerSbbUsage sbbu = getDefaultSbbUsageParameterSet(); sbbu.incrementErrorRecoverablePduException(ONE); sbbu.sampleRecoverablePduException(0L); logger.severe(String.format("\nonRecoverablePduException : RecoverablePduException=%s", event)); // TODO : Handle this } private void onSubmitSmLocal(final TxSmppServerSbbUsage anSbbUsage, final com.cloudhopper.smpp.pdu.SubmitSm event, final ActivityContextInterface aci) { // TODO remove it ........................... // long l2 = Date.parse(event.getServiceType()); // Date dt0 = new Date(l2); Date dt0 = new Date(); Date dt1 = new Date(); // TODO remove it ........................... SmppTransaction smppServerTransaction = (SmppTransaction) aci.getActivity(); Esme esme = smppServerTransaction.getEsme(); String esmeName = esme.getName(); if (this.logger.isFineEnabled()) { this.logger.fine("\nReceived SUBMIT_SM = " + event + " from Esme name=" + esmeName); } CheckMessageLimitResult cres = esme.onMessageReceived(1); if (cres.getResult() != CheckMessageLimitResult.Result.ok) { if (cres.getResult() == CheckMessageLimitResult.Result.firstFault) { this.updateOverrateCounters(cres); this.logger.info(cres.getMessage()); } SubmitSmResp response = event.createResponse(); response.setCommandStatus(SmppConstants.STATUS_THROTTLED); String s = cres.getMessage(); if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { anSbbUsage.incrementCounterErrorSubmitSm(ONE); this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorSubmitSmResponding(ONE); this.logger.severe("Error while trying to send SubmitSmResponse. Message: " + e.getMessage() + ".\nResponse: " + response + ".", e); } return; } Sms sms; try { TargetAddress ta = createDestTargetAddress(event.getDestAddress(), esme.getNetworkId()); sms = this.createSmsEvent(event, esme, ta, persistence); this.processSms(sms, persistence, esme, event, null, null, IncomingMessageType.submit_sm); } catch (SmscProcessingException e1) { anSbbUsage.incrementCounterErrorSubmitSm(ONE); SbbStatsUtils.handleProcessingException(e1, anSbbUsage); if (!e1.isSkipErrorLogging()) { this.logger.severe(e1.getMessage(), e1); smscStatAggregator.updateMsgInFailedAll(); } SubmitSmResp response = event.createResponse(); response.setCommandStatus(e1.getSmppErrorCode()); String s = e1.getMessage(); if (s != null) { if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorSubmitSmResponding(ONE); this.logger.severe("Error while trying to send SubmitSmResponse. Message: " + e.getMessage() + ".\nResponse: " + response + ".", e); } return; } catch (Throwable e1) { anSbbUsage.incrementCounterErrorSubmitSm(ONE); String s = "Exception when processing SubmitSm message: " + e1.getMessage(); this.logger.severe(s, e1); smscStatAggregator.updateMsgInFailedAll(); SubmitSmResp response = event.createResponse(); response.setCommandStatus(SmppConstants.STATUS_SYSERR); if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorSubmitSmResponding(ONE); this.logger.severe("Error while trying to send SubmitSmResponse. Message: " + e.getMessage() + ".\nResponse: " + response + ".", e); } return; } SubmitSmResp response = event.createResponse(); response.setMessageId(sms.getMessageIdText()); // Lets send the Response with success here try { if (sms.getMessageDeliveryResultResponse() == null) { this.smppServerSessions.sendResponsePdu(esme, event, response); } } catch (Throwable e) { anSbbUsage.incrementCounterErrorSubmitSmResponding(ONE); this.logger.severe("Error while trying to send SubmitSmResponse. Message: " + e.getMessage() + ".\nResponse: " + response + ".", e); } // TODO remove it ........................... Date dt3 = new Date(); SmscStatProvider.getInstance().setParam1((int) (dt3.getTime() - dt0.getTime())); SmscStatProvider.getInstance().setParam2((int) (dt3.getTime() - dt1.getTime())); // TODO remove it ........................... } private void onDataSmLocal(final TxSmppServerSbbUsage anSbbUsage, final com.cloudhopper.smpp.pdu.DataSm event, ActivityContextInterface aci) { SmppTransaction smppServerTransaction = (SmppTransaction) aci.getActivity(); Esme esme = smppServerTransaction.getEsme(); String esmeName = esme.getName(); if (this.logger.isFineEnabled()) { this.logger.fine("Received DATA_SM = " + event + " from Esme name=" + esmeName); } CheckMessageLimitResult cres = esme.onMessageReceived(1); if (cres.getResult() != CheckMessageLimitResult.Result.ok) { if (cres.getResult() == CheckMessageLimitResult.Result.firstFault) { this.updateOverrateCounters(cres); this.logger.info(cres.getMessage()); } DataSmResp response = event.createResponse(); response.setCommandStatus(SmppConstants.STATUS_THROTTLED); String s = cres.getMessage(); if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { anSbbUsage.incrementCounterErrorDataSm(ONE); this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorDataSmResponding(ONE); this.logger.severe("Error while trying to send DataSmResponse=" + response, e); } return; } Sms sms; try { TargetAddress ta = createDestTargetAddress(event.getDestAddress(), esme.getNetworkId()); sms = this.createSmsEvent(event, esme, ta, persistence); this.processSms(sms, persistence, esme, null, event, null, IncomingMessageType.data_sm); } catch (SmscProcessingException e1) { anSbbUsage.incrementCounterErrorDataSm(ONE); SbbStatsUtils.handleProcessingException(e1, anSbbUsage); if (!e1.isSkipErrorLogging()) { this.logger.severe(e1.getMessage(), e1); smscStatAggregator.updateMsgInFailedAll(); } DataSmResp response = event.createResponse(); response.setCommandStatus(e1.getSmppErrorCode()); String s = e1.getMessage(); if (s != null) { if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorDataSmResponding(ONE); this.logger.severe("Error while trying to send DataSmResponse=" + response, e); } return; } catch (Throwable e1) { anSbbUsage.incrementCounterErrorDataSm(ONE); String s = "Exception when processing dataSm message: " + e1.getMessage(); this.logger.severe(s, e1); smscStatAggregator.updateMsgInFailedAll(); DataSmResp response = event.createResponse(); response.setCommandStatus(SmppConstants.STATUS_SYSERR); if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorDataSmResponding(ONE); this.logger.severe("Error while trying to send SubmitSmResponse=" + response, e); } return; } DataSmResp response = event.createResponse(); response.setMessageId(sms.getMessageIdText()); // Lets send the Response with success here try { if (sms.getMessageDeliveryResultResponse() == null) { this.smppServerSessions.sendResponsePdu(esme, event, response); } } catch (Exception e) { anSbbUsage.incrementCounterErrorDataSmResponding(ONE); this.logger.severe("Error while trying to send DataSmResponse=" + response, e); } } private void onSubmitMultiLocal(final TxSmppServerSbbUsage anSbbUsage, final com.cloudhopper.smpp.pdu.SubmitMulti event, final ActivityContextInterface aci) { SmppTransaction smppServerTransaction = (SmppTransaction) aci.getActivity(); Esme esme = smppServerTransaction.getEsme(); String esmeName = esme.getName(); if (this.logger.isFineEnabled()) { this.logger.fine("\nReceived SUBMIT_MULTI = " + event + " from Esme name=" + esmeName); } List<Address> addrList = event.getDestAddresses(); int msgCnt = 0; if (addrList != null) msgCnt = addrList.size(); CheckMessageLimitResult cres = esme.onMessageReceived(msgCnt); if (cres.getResult() != CheckMessageLimitResult.Result.ok) { if (cres.getResult() == CheckMessageLimitResult.Result.firstFault) { this.updateOverrateCounters(cres); this.logger.info(cres.getMessage()); } SubmitMultiResp response = event.createResponse(); response.setCommandStatus(SmppConstants.STATUS_THROTTLED); String s = cres.getMessage(); if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { anSbbUsage.incrementCounterErrorSubmitMultiSm(ONE); this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorSubmitMultiSmResponding(ONE); this.logger.severe("Error while trying to send SubmitMultiResponse=" + response, e); } return; } SubmitMultiParseResult parseResult; try { parseResult = this.createSmsEventMulti(event, esme, persistence, esme.getNetworkId()); for (Sms sms : parseResult.getParsedMessages()) { this.processSms(sms, persistence, esme, null, null, event, IncomingMessageType.submit_multi); } } catch (SmscProcessingException e1) { anSbbUsage.incrementCounterErrorSubmitMultiSm(ONE); SbbStatsUtils.handleProcessingException(e1, anSbbUsage); if (!e1.isSkipErrorLogging()) { this.logger.severe(e1.getMessage(), e1); smscStatAggregator.updateMsgInFailedAll(); } SubmitMultiResp response = event.createResponse(); response.setCommandStatus(e1.getSmppErrorCode()); String s = e1.getMessage(); if (s != null) { if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorSubmitMultiSmResponding(ONE); this.logger.severe("Error while trying to send SubmitMultiResponse=" + response, e); } return; } catch (Throwable e1) { anSbbUsage.incrementCounterErrorSubmitMultiSm(ONE); String s = "Exception when processing SubmitMulti message: " + e1.getMessage(); this.logger.severe(s, e1); smscStatAggregator.updateMsgInFailedAll(); SubmitMultiResp response = event.createResponse(); response.setCommandStatus(SmppConstants.STATUS_SYSERR); if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); anSbbUsage.incrementCounterErrorSubmitMultiSmResponding(ONE); } catch (Exception e) { this.logger.severe("Error while trying to send SubmitMultiResponse=" + response, e); } return; } SubmitMultiResp response = event.createResponse(); Sms sms = null; if (parseResult.getParsedMessages().size() > 0) sms = parseResult.getParsedMessages().get(0); if (sms != null) response.setMessageId(sms.getMessageIdText()); for (UnsucessfulSME usme : parseResult.getBadAddresses()) { try { response.addUnsucessfulSME(usme); } catch (SmppInvalidArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // Lets send the Response with success here try { if (sms == null || sms.getMessageDeliveryResultResponse() == null) { this.smppServerSessions.sendResponsePdu(esme, event, response); } } catch (Throwable e) { anSbbUsage.incrementCounterErrorSubmitMultiSmResponding(ONE); this.logger.severe("Error while trying to send SubmitMultiResponse=" + response, e); } } private void onDeliverSmLocal(final TxSmppServerSbbUsage anSbbUsage, final com.cloudhopper.smpp.pdu.DeliverSm event, final ActivityContextInterface aci) { SmppTransaction smppServerTransaction = (SmppTransaction) aci.getActivity(); Esme esme = smppServerTransaction.getEsme(); String esmeName = esme.getName(); if (this.logger.isFineEnabled()) { this.logger.fine("\nReceived DELIVER_SM = " + event + " from Esme name=" + esmeName); } CheckMessageLimitResult cres = esme.onMessageReceived(1); if (cres.getResult() != CheckMessageLimitResult.Result.ok) { if (cres.getResult() == CheckMessageLimitResult.Result.firstFault) { this.updateOverrateCounters(cres); this.logger.info(cres.getMessage()); } DeliverSmResp response = event.createResponse(); response.setCommandStatus(SmppConstants.STATUS_THROTTLED); String s = cres.getMessage(); if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { anSbbUsage.incrementCounterErrorDeliverSm(ONE); this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorDeliverSmResponding(ONE); this.logger.severe("Error while trying to send DeliverSmResponse=" + response, e); } return; } Sms sms; try { TargetAddress ta = createDestTargetAddress(event.getDestAddress(), esme.getNetworkId()); sms = this.createSmsEvent(event, esme, ta, persistence); this.processSms(sms, persistence, esme, null, null, null, IncomingMessageType.deliver_sm); } catch (SmscProcessingException e1) { anSbbUsage.incrementCounterErrorDeliverSm(ONE); SbbStatsUtils.handleProcessingException(e1, anSbbUsage); if (!e1.isSkipErrorLogging()) { this.logger.severe(e1.getMessage(), e1); smscStatAggregator.updateMsgInFailedAll(); } DeliverSmResp response = event.createResponse(); response.setCommandStatus(e1.getSmppErrorCode()); String s = e1.getMessage(); if (s != null) { if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorDeliverSmResponding(ONE); this.logger.severe("Error while trying to send SubmitSmResponse=" + response, e); } return; } catch (Throwable e1) { anSbbUsage.incrementCounterErrorDeliverSm(ONE); String s = "Exception when processing SubmitSm message: " + e1.getMessage(); this.logger.severe(s, e1); smscStatAggregator.updateMsgInFailedAll(); DeliverSmResp response = event.createResponse(); response.setCommandStatus(SmppConstants.STATUS_SYSERR); if (s.length() > 255) s = s.substring(0, 255); Tlv tlv; try { tlv = TlvUtil.createNullTerminatedStringTlv(SmppConstants.TAG_ADD_STATUS_INFO, s); response.addOptionalParameter(tlv); } catch (TlvConvertException e) { this.logger.severe("TlvConvertException while storing TAG_ADD_STATUS_INFO Tlv parameter", e); } // Lets send the Response with error here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Exception e) { anSbbUsage.incrementCounterErrorDeliverSmResponding(ONE); this.logger.severe("Error while trying to send SubmitSmResponse=" + response, e); } return; } DeliverSmResp response = event.createResponse(); response.setMessageId(sms.getMessageIdText()); // Lets send the Response with success here try { this.smppServerSessions.sendResponsePdu(esme, event, response); } catch (Throwable e) { anSbbUsage.incrementCounterErrorDeliverSmResponding(ONE); this.logger.severe("Error while trying to send SubmitSmResponse=" + response, e); } } // ********* // General Sms creating and processing methods protected Sms createSmsEvent(BaseSm event, Esme origEsme, TargetAddress ta, PersistenceRAInterface store) throws SmscProcessingException { Sms sms = new Sms(); sms.setDbId(UUID.randomUUID()); sms.setOriginationType(OriginationType.SMPP); // checking parameters first if (event.getSourceAddress() == null || event.getSourceAddress().getAddress() == null || event.getSourceAddress().getAddress().isEmpty()) { throw new SmscProcessingException("SourceAddress digits are absent", SmppConstants.STATUS_INVSRCADR, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_SRC_ADDR_INVALID); } sms.setSourceAddr(event.getSourceAddress().getAddress()); sms.setSourceAddrTon(event.getSourceAddress().getTon()); sms.setSourceAddrNpi(event.getSourceAddress().getNpi()); sms.setOrigNetworkId(origEsme.getNetworkId()); int dcs = event.getDataCoding(); String err = MessageUtil.checkDataCodingSchemeSupport(dcs); if (err != null) { throw new SmscProcessingException("TxSmpp DataCoding scheme does not supported: " + dcs + " - " + err, SmppExtraConstants.ESME_RINVDCS, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_DATA_CODING_INVALID); } // storing additional parameters ArrayList<Tlv> optionalParameters = event.getOptionalParameters(); if (optionalParameters != null && optionalParameters.size() > 0) { for (Tlv tlv : optionalParameters) { if (tlv.getTag() != SmppConstants.TAG_MESSAGE_PAYLOAD) { sms.getTlvSet().addOptionalParameter(tlv); } } } DataCodingScheme dataCodingScheme = new DataCodingSchemeImpl(dcs); sms.setDataCoding(dcs); sms.setOrigSystemId(origEsme.getSystemId()); sms.setOrigEsmeName(origEsme.getName()); sms.setSubmitDate(new Timestamp(System.currentTimeMillis())); sms.setServiceType(event.getServiceType()); sms.setEsmClass(event.getEsmClass()); sms.setProtocolId(event.getProtocolId()); sms.setPriority(event.getPriority()); sms.setRegisteredDelivery(event.getRegisteredDelivery()); sms.setReplaceIfPresent(event.getReplaceIfPresent()); sms.setDefaultMsgId(event.getDefaultMsgId()); boolean udhPresent = (event.getEsmClass() & SmppConstants.ESM_CLASS_UDHI_MASK) != 0; Tlv sarMsgRefNum = event.getOptionalParameter(SmppConstants.TAG_SAR_MSG_REF_NUM); Tlv sarTotalSegments = event.getOptionalParameter(SmppConstants.TAG_SAR_TOTAL_SEGMENTS); Tlv sarSegmentSeqnum = event.getOptionalParameter(SmppConstants.TAG_SAR_SEGMENT_SEQNUM); boolean segmentTlvFlag = (sarMsgRefNum != null && sarTotalSegments != null && sarSegmentSeqnum != null); // short message data byte[] data = event.getShortMessage(); if (event.getShortMessageLength() == 0) { // Probably the message_payload Optional Parameter is being used Tlv messagePaylod = event.getOptionalParameter(SmppConstants.TAG_MESSAGE_PAYLOAD); if (messagePaylod != null) { data = messagePaylod.getValue(); } } if (data == null) { data = new byte[0]; } byte[] udhData; byte[] textPart; String msg; udhData = null; textPart = data; if (udhPresent && data.length > 2) { // UDH exists int udhLen = (textPart[0] & 0xFF) + 1; if (udhLen <= textPart.length) { textPart = new byte[textPart.length - udhLen]; udhData = new byte[udhLen]; System.arraycopy(data, udhLen, textPart, 0, textPart.length); System.arraycopy(data, 0, udhData, 0, udhLen); } } if (dataCodingScheme.getCharacterSet() == CharacterSet.GSM8) { msg = new String(textPart, isoCharset); } else { SmppEncoding enc; if (dataCodingScheme.getCharacterSet() == CharacterSet.GSM7) { enc = smscPropertiesManagement.getSmppEncodingForGsm7(); } else { enc = smscPropertiesManagement.getSmppEncodingForUCS2(); } switch (enc) { case Utf8: default: msg = new String(textPart, utf8Charset); break; case Unicode: msg = new String(textPart, ucs2Charset); break; case Gsm7: GSMCharsetDecoder decoder = (GSMCharsetDecoder) gsm7Charset.newDecoder(); decoder.setGSMCharsetDecodingData(new GSMCharsetDecodingData(Gsm7EncodingStyle.bit8_smpp_style, Integer.MAX_VALUE, 0)); ByteBuffer bb = ByteBuffer.wrap(textPart); CharBuffer bf = null; try { bf = decoder.decode(bb); } catch (CharacterCodingException e) { // this can not be } msg = bf.toString(); break; } } sms.setShortMessageText(msg); sms.setShortMessageBin(udhData); // checking of min / max length if (origEsme.getMinMessageLength() >= 0 && msg.length() < origEsme.getMinMessageLength()) { SmscProcessingException e = new SmscProcessingException( "Message length is less than a min length limit for ESME=" + origEsme.getName() + ", len=" + msg.length(), SmppConstants.STATUS_INVMSGLEN, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_MSG_TOO_SHORT); e.setSkipErrorLogging(true); throw e; } if (origEsme.getMaxMessageLength() >= 0 && msg.length() > origEsme.getMaxMessageLength()) { SmscProcessingException e = new SmscProcessingException( "Message length is more than a max length limit for ESME=" + origEsme.getName() + ", len=" + msg.length(), SmppConstants.STATUS_INVMSGLEN, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_MSG_TOO_LONG); e.setSkipErrorLogging(true); throw e; } // checking max message length if (udhPresent || segmentTlvFlag) { // here splitting by SMSC is not supported UserDataHeader udh = null; int lenSolid = MessageUtil.getMaxSolidMessageBytesLength(); if (udhPresent) { udh = new UserDataHeaderImpl(udhData); } else { udh = createNationalLanguageUdh(origEsme, dataCodingScheme); if (udh != null && udh.getNationalLanguageLockingShift() != null) { lenSolid -= 3; sms.setNationalLanguageLockingShift(udh.getNationalLanguageLockingShift().getNationalLanguageIdentifier() .getCode()); } if (udh != null && udh.getNationalLanguageSingleShift() != null) { lenSolid -= 3; sms.setNationalLanguageSingleShift(udh.getNationalLanguageSingleShift().getNationalLanguageIdentifier() .getCode()); } } int messageLen = MessageUtil.getMessageLengthInBytes(dataCodingScheme, msg, udh); if (udhData != null) lenSolid -= udhData.length; if (messageLen > lenSolid) { throw new SmscProcessingException( "Message length in bytes is too big for solid message: " + messageLen + ">" + lenSolid, SmppConstants.STATUS_INVPARLEN, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_MSG_TOO_LONG); } } else { // here splitting by SMSC is supported int lenSegmented = MessageUtil.getMaxSegmentedMessageBytesLength(); UserDataHeader udh = createNationalLanguageUdh(origEsme, dataCodingScheme); if (msg.length() * 2 > (lenSegmented - 6) * 255) { // firstly draft length check int messageLen = MessageUtil.getMessageLengthInBytes(dataCodingScheme, msg, udh); if (udh != null) { if (udh.getNationalLanguageLockingShift() != null) { lenSegmented -= 3; sms.setNationalLanguageLockingShift(udh.getNationalLanguageLockingShift() .getNationalLanguageIdentifier().getCode()); } if (udh.getNationalLanguageSingleShift() != null) { lenSegmented -= 3; sms.setNationalLanguageSingleShift(udh.getNationalLanguageSingleShift().getNationalLanguageIdentifier() .getCode()); } } if (messageLen > lenSegmented * 255) { throw new SmscProcessingException( "Message length in bytes is too big for segmented message: " + messageLen + ">" + lenSegmented, SmppConstants.STATUS_INVPARLEN, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_MSG_TOO_LONG); } } else { if (udh != null) { if (udh.getNationalLanguageLockingShift() != null) { sms.setNationalLanguageLockingShift(udh.getNationalLanguageLockingShift() .getNationalLanguageIdentifier().getCode()); } if (udh.getNationalLanguageSingleShift() != null) { sms.setNationalLanguageSingleShift(udh.getNationalLanguageSingleShift().getNationalLanguageIdentifier() .getCode()); } } } } // ValidityPeriod processing Tlv tlvQosTimeToLive = event.getOptionalParameter(SmppConstants.TAG_QOS_TIME_TO_LIVE); Date validityPeriod; if (tlvQosTimeToLive != null) { long valTime; try { valTime = (new Date()).getTime() + tlvQosTimeToLive.getValueAsInt(); } catch (TlvConvertException e) { throw new SmscProcessingException( "TlvConvertException when getting TAG_QOS_TIME_TO_LIVE tlv field: " + e.getMessage(), SmppConstants.STATUS_INVOPTPARAMVAL, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_MISC_VALIDITY_PERIOD_PARSING); } validityPeriod = new Date(valTime); } else { try { validityPeriod = MessageUtil.parseSmppDate(event.getValidityPeriod()); } catch (ParseException e) { throw new SmscProcessingException( "ParseException when parsing ValidityPeriod field: " + e.getMessage(), SmppConstants.STATUS_INVEXPIRY, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_MISC_VALIDITY_PERIOD_PARSING); } } MessageUtil.applyValidityPeriod(sms, validityPeriod, true, smscPropertiesManagement.getMaxValidityPeriodHours(), smscPropertiesManagement.getDefaultValidityPeriodHours()); // ScheduleDeliveryTime processing Date scheduleDeliveryTime; try { scheduleDeliveryTime = MessageUtil.parseSmppDate(event.getScheduleDeliveryTime()); } catch (ParseException e) { throw new SmscProcessingException("ParseException when parsing ScheduleDeliveryTime field: " + e.getMessage(), SmppConstants.STATUS_INVSCHED, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_MISC_SCHEDULER_DELIVERY_TIME_PARSING); } MessageUtil.applyScheduleDeliveryTime(sms, scheduleDeliveryTime); SmsSet smsSet; smsSet = new SmsSet(); smsSet.setDestAddr(ta.getAddr()); smsSet.setDestAddrNpi(ta.getAddrNpi()); smsSet.setDestAddrTon(ta.getAddrTon()); smsSet.setNetworkId(origEsme.getNetworkId()); smsSet.addSms(sms); sms.setSmsSet(smsSet); long messageId = store.c2_getNextMessageId(); SmscStatProvider.getInstance().setCurrentMessageId(messageId); sms.setMessageId(messageId); // TODO: process case when event.getReplaceIfPresent()==true: we need // remove old message with same MessageId ? return sms; } protected SubmitMultiParseResult createSmsEventMulti(SubmitMulti event, Esme origEsme, PersistenceRAInterface store, int networkId) throws SmscProcessingException { List<Address> addrList = event.getDestAddresses(); if (addrList == null || addrList.size() == 0) { throw new SmscProcessingException("For received SubmitMulti no DestAddresses found: ", SmppConstants.STATUS_INVDLNAME, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_DST_ADDR_INVALID); } if (event.getSourceAddress() == null || event.getSourceAddress().getAddress() == null || event.getSourceAddress().getAddress().isEmpty()) { throw new SmscProcessingException("SourceAddress digits are absent", SmppConstants.STATUS_INVSRCADR, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_SRC_ADDR_INVALID); } // checking parameters first String sourceAddr = event.getSourceAddress().getAddress(); int sourceAddrTon = event.getSourceAddress().getTon(); int sourceAddrNpi = event.getSourceAddress().getNpi(); int dcs = event.getDataCoding(); String err = MessageUtil.checkDataCodingSchemeSupport(dcs); if (err != null) { throw new SmscProcessingException("TxSmpp DataCoding scheme does not supported: " + dcs + " - " + err, SmppExtraConstants.ESME_RINVDCS, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_DATA_CODING_INVALID); } DataCodingScheme dataCodingScheme = new DataCodingSchemeImpl(dcs); boolean udhPresent = (event.getEsmClass() & SmppConstants.ESM_CLASS_UDHI_MASK) != 0; Tlv sarMsgRefNum = event.getOptionalParameter(SmppConstants.TAG_SAR_MSG_REF_NUM); Tlv sarTotalSegments = event.getOptionalParameter(SmppConstants.TAG_SAR_TOTAL_SEGMENTS); Tlv sarSegmentSeqnum = event.getOptionalParameter(SmppConstants.TAG_SAR_SEGMENT_SEQNUM); boolean segmentTlvFlag = (sarMsgRefNum != null && sarTotalSegments != null && sarSegmentSeqnum != null); // short message data byte[] data = event.getShortMessage(); if (event.getShortMessageLength() == 0) { // Probably the message_payload Optional Parameter is being used Tlv messagePaylod = event.getOptionalParameter(SmppConstants.TAG_MESSAGE_PAYLOAD); if (messagePaylod != null) { data = messagePaylod.getValue(); } } if (data == null) { data = new byte[0]; } byte[] udhData; byte[] textPart; String msg; udhData = null; textPart = data; if (udhPresent && data.length > 2) { // UDH exists int udhLen = (textPart[0] & 0xFF) + 1; if (udhLen <= textPart.length) { textPart = new byte[textPart.length - udhLen]; udhData = new byte[udhLen]; System.arraycopy(data, udhLen, textPart, 0, textPart.length); System.arraycopy(data, 0, udhData, 0, udhLen); } } if (dataCodingScheme.getCharacterSet() == CharacterSet.GSM8) { msg = new String(textPart, isoCharset); } else { SmppEncoding enc; if (dataCodingScheme.getCharacterSet() == CharacterSet.GSM7) { enc = smscPropertiesManagement.getSmppEncodingForGsm7(); } else { enc = smscPropertiesManagement.getSmppEncodingForUCS2(); } switch (enc) { case Utf8: default: msg = new String(textPart, utf8Charset); break; case Unicode: msg = new String(textPart, ucs2Charset); break; case Gsm7: GSMCharsetDecoder decoder = (GSMCharsetDecoder) gsm7Charset.newDecoder(); decoder.setGSMCharsetDecodingData(new GSMCharsetDecodingData(Gsm7EncodingStyle.bit8_smpp_style, Integer.MAX_VALUE, 0)); ByteBuffer bb = ByteBuffer.wrap(textPart); CharBuffer bf = null; try { bf = decoder.decode(bb); } catch (CharacterCodingException e) { // this can not be } msg = bf.toString(); break; } } // checking max message length int nationalLanguageLockingShift = 0; int nationalLanguageSingleShift = 0; if (udhPresent || segmentTlvFlag) { // here splitting by SMSC is not supported UserDataHeader udh = null; int lenSolid = MessageUtil.getMaxSolidMessageBytesLength(); if (udhPresent) udh = new UserDataHeaderImpl(udhData); else { udh = createNationalLanguageUdh(origEsme, dataCodingScheme); if (udh.getNationalLanguageLockingShift() != null) { lenSolid -= 3; nationalLanguageLockingShift = udh.getNationalLanguageLockingShift().getNationalLanguageIdentifier() .getCode(); } if (udh.getNationalLanguageSingleShift() != null) { lenSolid -= 3; nationalLanguageSingleShift = udh.getNationalLanguageSingleShift().getNationalLanguageIdentifier() .getCode(); } } int messageLen = MessageUtil.getMessageLengthInBytes(dataCodingScheme, msg, udh); if (udhData != null) messageLen += udhData.length; if (messageLen > lenSolid) { throw new SmscProcessingException( "Message length in bytes is too big for solid message: " + messageLen + ">" + lenSolid, SmppConstants.STATUS_INVPARLEN, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_MSG_TOO_LONG); } } else { // here splitting by SMSC is supported int lenSegmented = MessageUtil.getMaxSegmentedMessageBytesLength(); if (msg.length() * 2 > (lenSegmented - 6) * 255) { // firstly draft length check UserDataHeader udh = createNationalLanguageUdh(origEsme, dataCodingScheme); int messageLen = MessageUtil.getMessageLengthInBytes(dataCodingScheme, msg, udh); if (udh.getNationalLanguageLockingShift() != null) { lenSegmented -= 3; nationalLanguageLockingShift = udh.getNationalLanguageLockingShift().getNationalLanguageIdentifier() .getCode(); } if (udh.getNationalLanguageSingleShift() != null) { lenSegmented -= 3; nationalLanguageSingleShift = udh.getNationalLanguageSingleShift().getNationalLanguageIdentifier() .getCode(); } if (messageLen > lenSegmented * 255) { throw new SmscProcessingException( "Message length in bytes is too big for segmented message: " + messageLen + ">" + lenSegmented, SmppConstants.STATUS_INVPARLEN, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_MISC_MSG_TOO_LONG); } } } // ValidityPeriod processing Tlv tlvQosTimeToLive = event.getOptionalParameter(SmppConstants.TAG_QOS_TIME_TO_LIVE); Date validityPeriod; if (tlvQosTimeToLive != null) { long valTime; try { valTime = (new Date()).getTime() + tlvQosTimeToLive.getValueAsInt(); } catch (TlvConvertException e) { throw new SmscProcessingException( "TlvConvertException when getting TAG_QOS_TIME_TO_LIVE tlv field: " + e.getMessage(), SmppConstants.STATUS_INVOPTPARAMVAL, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_MISC_VALIDITY_PERIOD_PARSING); } validityPeriod = new Date(valTime); } else { try { validityPeriod = MessageUtil.parseSmppDate(event.getValidityPeriod()); } catch (ParseException e) { throw new SmscProcessingException("ParseException when parsing ValidityPeriod field: " + e.getMessage(), SmppConstants.STATUS_INVEXPIRY, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_MISC_VALIDITY_PERIOD_PARSING); } } // ScheduleDeliveryTime processing Date scheduleDeliveryTime; try { scheduleDeliveryTime = MessageUtil.parseSmppDate(event.getScheduleDeliveryTime()); } catch (ParseException e) { throw new SmscProcessingException("ParseException when parsing ScheduleDeliveryTime field: " + e.getMessage(), SmppConstants.STATUS_INVSCHED, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_MISC_SCHEDULER_DELIVERY_TIME_PARSING); } long messageId = store.c2_getNextMessageId(); SmscStatProvider.getInstance().setCurrentMessageId(messageId); ArrayList<Sms> msgList = new ArrayList<Sms>(addrList.size()); ArrayList<UnsucessfulSME> badAddresses = new ArrayList<UnsucessfulSME>(addrList.size()); for (Address address : addrList) { boolean succAddr = false; TargetAddress ta = null; try { ta = createDestTargetAddress(address, networkId); succAddr = true; } catch (SmscProcessingException e) { Address addr = (Address) e.getExtraErrorData(); if (addr != null) { UnsucessfulSME asme = new UnsucessfulSME(e.getSmppErrorCode(), addr); badAddresses.add(asme); } } if (succAddr) { Sms sms = new Sms(); sms.setDbId(UUID.randomUUID()); sms.setOriginationType(OriginationType.SMPP); sms.setSourceAddr(sourceAddr); sms.setSourceAddrTon(sourceAddrTon); sms.setSourceAddrNpi(sourceAddrNpi); sms.setOrigNetworkId(networkId); sms.setDataCoding(dcs); sms.setNationalLanguageLockingShift(nationalLanguageLockingShift); sms.setNationalLanguageSingleShift(nationalLanguageSingleShift); sms.setOrigSystemId(origEsme.getSystemId()); sms.setOrigEsmeName(origEsme.getName()); sms.setSubmitDate(new Timestamp(System.currentTimeMillis())); sms.setServiceType(event.getServiceType()); sms.setEsmClass(event.getEsmClass()); sms.setProtocolId(event.getProtocolId()); sms.setPriority(event.getPriority()); sms.setRegisteredDelivery(event.getRegisteredDelivery()); sms.setReplaceIfPresent(event.getReplaceIfPresent()); sms.setDefaultMsgId(event.getDefaultMsgId()); sms.setShortMessageText(msg); sms.setShortMessageBin(udhData); MessageUtil.applyValidityPeriod(sms, validityPeriod, true, smscPropertiesManagement.getMaxValidityPeriodHours(), smscPropertiesManagement.getDefaultValidityPeriodHours()); MessageUtil.applyScheduleDeliveryTime(sms, scheduleDeliveryTime); // storing additional parameters ArrayList<Tlv> optionalParameters = event.getOptionalParameters(); if (optionalParameters != null && optionalParameters.size() > 0) { for (Tlv tlv : optionalParameters) { if (tlv.getTag() != SmppConstants.TAG_MESSAGE_PAYLOAD) { sms.getTlvSet().addOptionalParameter(tlv); } } } SmsSet smsSet; smsSet = new SmsSet(); smsSet.setDestAddr(ta.getAddr()); smsSet.setDestAddrNpi(ta.getAddrNpi()); smsSet.setDestAddrTon(ta.getAddrTon()); smsSet.setNetworkId(origEsme.getNetworkId()); smsSet.addSms(sms); sms.setSmsSet(smsSet); sms.setMessageId(messageId); msgList.add(sms); } } // TODO: process case when event.getReplaceIfPresent()==true: we need // remove old message with same MessageId ? return new SubmitMultiParseResult(msgList, badAddresses); } private void processSms(Sms sms0, PersistenceRAInterface store, Esme esme, SubmitSm eventSubmit, DataSm eventData, SubmitMulti eventSubmitMulti, IncomingMessageType incomingMessageType) throws SmscProcessingException { if (logger.isInfoEnabled()) { logger.info(String.format("\nReceived %s to ESME: %s, sms=%s", incomingMessageType.toString(), esme.getName(), sms0.toString())); } this.checkSmscState(sms0, smscCongestionControl, SubmitCommonSbb.MaxActivityCountFactor.factor_12); // // checking if SMSC is stopped // if (smscPropertiesManagement.isSmscStopped()) { // SmscProcessingException e = new SmscProcessingException("SMSC is stopped", SmppConstants.STATUS_SYSERR, 0, null); // e.setSkipErrorLogging(true); // throw e; // } // // checking if SMSC is paused // if (smscPropertiesManagement.isDeliveryPause() // && (!MessageUtil.isStoreAndForward(sms0) || smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast)) { // SmscProcessingException e = new SmscProcessingException("SMSC is paused", SmppConstants.STATUS_SYSERR, 0, null); // e.setSkipErrorLogging(true); // throw e; // } // // checking if cassandra database is available // if (!store.isDatabaseAvailable() && MessageUtil.isStoreAndForward(sms0)) { // SmscProcessingException e = new SmscProcessingException("Database is unavailable", SmppConstants.STATUS_SYSERR, 0, // null); // e.setSkipErrorLogging(true); // throw e; // } // if (!MessageUtil.isStoreAndForward(sms0) // || smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast) { // // checking if delivery query is overloaded // int fetchMaxRows = (int) (smscPropertiesManagement.getMaxActivityCount() * 1.2); // int activityCount = SmsSetCache.getInstance().getProcessingSmsSetSize(); // if (activityCount >= fetchMaxRows) { // smscCongestionControl.registerMaxActivityCount1_2Threshold(); // SmscProcessingException e = new SmscProcessingException("SMSC is overloaded", SmppConstants.STATUS_THROTTLED, // 0, null); // e.setSkipErrorLogging(true); // throw e; // } else { // smscCongestionControl.registerMaxActivityCount1_2BackToNormal(); // } // } boolean withCharging = false; switch (smscPropertiesManagement.getTxSmppChargingType()) { case Selected: withCharging = esme.isChargingEnabled(); break; case All: withCharging = true; break; } // transactional mode / or charging request boolean isTransactional = (eventSubmit != null || eventData != null) && MessageUtil.isTransactional(sms0); if (isTransactional || withCharging) { MessageDeliveryResultResponseSmpp messageDeliveryResultResponse = new MessageDeliveryResultResponseSmpp( !isTransactional, this.smppServerSessions, esme, eventSubmit, eventData, sms0.getMessageId()); sms0.setMessageDeliveryResultResponse(messageDeliveryResultResponse); } // delivery receipt transit - replacing of messageId in delivery receipt with local messageId if (smscPropertiesManagement.getIncomeReceiptsProcessing() && MessageUtil.isDeliveryReceipt(sms0)) { DeliveryReceiptData deliveryReceiptData = MessageUtil.parseDeliveryReceipt(sms0.getShortMessageText(), sms0.getTlvSet()); if (deliveryReceiptData != null) { String clusterName = esme.getClusterName(); String dlvTlvMessageId = deliveryReceiptData.getTlvReceiptedMessageId(); String dlvMessageId = deliveryReceiptData.getMessageId(); Long messageId = null; String drFormat = null; if (dlvTlvMessageId != null) { try { messageId = persistence.c2_getMessageIdByRemoteMessageId(dlvTlvMessageId, clusterName); drFormat = "dlvTlvMessageId"; } catch (PersistenceException e) { logger.severe("Exception when running c2_getMessageIdByRemoteMessageId() - 1: " + e.getMessage(), e); } } if (messageId == null) { // trying to parse as a hex format try { messageId = persistence.c2_getMessageIdByRemoteMessageId(dlvMessageId, clusterName); drFormat = "dlvMessageId"; } catch (PersistenceException e) { logger.severe("Exception when running c2_getMessageIdByRemoteMessageId() - 2: " + e.getMessage(), e); } catch (NumberFormatException e) { } } if (messageId != null) { // we found in local cache / database a reference to an origin logger.info("Remote delivery receipt: clusterName=" + clusterName + ", dlvMessageId=" + dlvMessageId + ", dlvTlvMessageId=" + dlvTlvMessageId + ", receipt=" + sms0.getShortMessageText() + ", drFormat=" + drFormat); if (dlvTlvMessageId != null) { sms0.setReceiptOrigMessageId(dlvTlvMessageId); sms0.getTlvSet().removeOptionalParameter(SmppConstants.TAG_RECEIPTED_MSG_ID); } else { sms0.setReceiptOrigMessageId(dlvMessageId); } sms0.setReceiptLocalMessageId(messageId); String messageIdStr = MessageUtil.createMessageIdString(messageId); String updatedReceiptText = MessageUtil.createDeliveryReceiptMessage(messageIdStr, deliveryReceiptData .getSubmitDate(), deliveryReceiptData.getDoneDate(), deliveryReceiptData.getError(), deliveryReceiptData.getText(), deliveryReceiptData.getStatus().equals(MessageUtil.DELIVERY_ACK_STATE_DELIVERED), null, deliveryReceiptData.getStatus().equals(MessageUtil.DELIVERY_ACK_STATE_ENROUTE)); sms0.setShortMessageText(updatedReceiptText); } else { // we have not found a local message - marking as unrecognized receipt logger.warning("Remote delivery receipt - but no original message is found in local cache: clusterName=" + clusterName + ", dlvMessageId=" + dlvMessageId + ", dlvTlvMessageId=" + dlvTlvMessageId + ", receipt=" + sms0.getShortMessageText() + ", drFormat=" + drFormat); sms0.setReceiptLocalMessageId(-1L); } } } this.forwardMessage(sms0, withCharging, smscStatAggregator); // if (withCharging) { // ChargingSbbLocalObject chargingSbb = getChargingSbbObject(); // chargingSbb.setupChargingRequestInterface(ChargingMedium.TxSmppOrig, sms0); // } else { // // applying of MProc // MProcResult mProcResult = MProcManagement.getInstance().applyMProcArrival(sms0, persistence); // // FastList<Sms> smss = mProcResult.getMessageList(); // for (FastList.Node<Sms> n = smss.head(), end = smss.tail(); (n = n.getNext()) != end;) { // Sms sms = n.getValue(); // TargetAddress ta = new TargetAddress(sms.getSmsSet()); // TargetAddress lock = store.obtainSynchroObject(ta); // // try { // synchronized (lock) { // boolean storeAndForwMode = MessageUtil.isStoreAndForward(sms); // if (!storeAndForwMode) { // try { // this.scheduler.injectSmsOnFly(sms.getSmsSet(), true); // } catch (Exception e) { // throw new SmscProcessingException("Exception when runnung injectSmsOnFly(): " + e.getMessage(), SmppConstants.STATUS_SYSERR, // MAPErrorCode.systemFailure, null, e); // } // } else { // // store and forward // if (smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast && sms.getScheduleDeliveryTime() == null) { // try { // sms.setStoringAfterFailure(true); // this.scheduler.injectSmsOnFly(sms.getSmsSet(), true); // } catch (Exception e) { // throw new SmscProcessingException("Exception when runnung injectSmsOnFly(): " + e.getMessage(), // SmppConstants.STATUS_SYSERR, MAPErrorCode.systemFailure, null, e); // } // } else { // try { // sms.setStored(true); // this.scheduler.setDestCluster(sms.getSmsSet()); // store.c2_scheduleMessage_ReschedDueSlot(sms, // smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast, // false); // } catch (PersistenceException e) { // throw new SmscProcessingException("PersistenceException when storing LIVE_SMS : " + e.getMessage(), // SmppConstants.STATUS_SUBMITFAIL, MAPErrorCode.systemFailure, null, e); // } // } // } // } // } finally { // store.releaseSynchroObject(lock); // } // } // // if (mProcResult.isMessageRejected()) { // sms0.setMessageDeliveryResultResponse(null); // SmscProcessingException e = new SmscProcessingException("Message is rejected by MProc rules", // SmppConstants.STATUS_SUBMITFAIL, 0, null); // e.setSkipErrorLogging(true); // if (logger.isInfoEnabled()) { // logger.info("Incoming message is rejected by mProc rules, message=[" + sms0 + "]"); // } // throw e; // } // if (mProcResult.isMessageDropped()) { // sms0.setMessageDeliveryResultResponse(null); // smscStatAggregator.updateMsgInFailedAll(); // if (logger.isInfoEnabled()) { // logger.info("Incoming message is dropped by mProc rules, message=[" + sms0 + "]"); // } // return; // } // // smscStatAggregator.updateMsgInReceivedAll(); // smscStatAggregator.updateMsgInReceivedSmpp(); // } } // ********* // private methods private void updateOverrateCounters(CheckMessageLimitResult cres) { switch (cres.getDomain()) { case perSecond: smscStatAggregator.updateSmppSecondRateOverlimitFail(); break; case perMinute: smscStatAggregator.updateSmppMinuteRateOverlimitFail(); break; case perHour: smscStatAggregator.updateSmppHourRateOverlimitFail(); break; case perDay: smscStatAggregator.updateSmppDayRateOverlimitFail(); break; } } private TargetAddress createDestTargetAddress(Address addr, int networkId) throws SmscProcessingException { if (addr == null || addr.getAddress() == null || addr.getAddress().isEmpty()) { throw new SmscProcessingException("DestAddress digits are absent", SmppConstants.STATUS_INVDSTADR, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, addr, SmscProcessingException.INTERNAL_ERROR_MISC_DST_ADDR_INVALID); } int destTon = addr.getTon(); int destNpi = addr.getNpi(); TargetAddress ta = new TargetAddress(destTon, destNpi, addr.getAddress(), networkId); return ta; } private UserDataHeader createNationalLanguageUdh(Esme origEsme, DataCodingScheme dataCodingScheme) { UserDataHeader udh = null; int nationalLanguageSingleShift = 0; int nationalLanguageLockingShift = 0; if (dataCodingScheme.getCharacterSet() == CharacterSet.GSM7) { nationalLanguageSingleShift = origEsme.getNationalLanguageSingleShift(); nationalLanguageLockingShift = origEsme.getNationalLanguageLockingShift(); if (nationalLanguageSingleShift == -1) nationalLanguageSingleShift = smscPropertiesManagement.getNationalLanguageSingleShift(); if (nationalLanguageLockingShift == -1) nationalLanguageLockingShift = smscPropertiesManagement.getNationalLanguageLockingShift(); } return MessageUtil.getNationalLanguageIdentifierUdh(nationalLanguageLockingShift, nationalLanguageSingleShift); } public enum IncomingMessageType { submit_sm, data_sm, deliver_sm, submit_multi, } }