Introduction
I gained some SMPP knowledge from one of my former jobs. After quitting the job, I wrote this library in my leisure time. Basically, what I did was to design the inheritance of the packets in a logic way, so far I think, and encode and decode the packets based on the SMPP specifications. Hope you guys like it.
SMPPLIB is a packet library for sending and receiving SMS messages (2-way SMS) based on SMPP specification v3.4 (partial support). The library is dependent on MFC (but what it depends on is CString
and Winsock initialization only, I may strip off the dependence in future release).
The SMPPLIB is a building block for developing Short Message Service (SMS) value added services. It provides a simple solution to solve the interface problem with Short Message Service Center (SMSC).
Basically, there are plenty of classes for most packets defined in the SMPP specification, together with three ESME entities, which are EsmeTransmitter
, EsmeReceiver
and EsmeTransceiver
. Usually, in the SMPP protocol, it works in the way that an ESME sends a command packet to the SMSC, then the SMSC replies with a reply packet. The same holds when the SMSC sends a packet to the ESME to indicate something, then the ESME sends back a reply packet to the SMSC.
Using the API to send a SMS message is easy.
EsmeTransmitter trans;
CSmppAddress scr(2, 0, "85291234567");
trans.init("212.5.192.111", 5055);
trans.bind("t_test", "testpwd", "", scr);
trans.submitMessage("Hiya, this is my message", "85291111888", 2, 0);
Usage Instruction
The DLL library is built with SMPPLIB_EXPORTING
defined, so when using it, this variable should not be defined. If the symbol is not defined, the classes in the SMPPLIB are imported using __declspec(dllimport)
.
To use the DLL, just put the Smpplib.dll and Smpplib.lib into a searchable directory of your application, and set your project options to link with Smpplib.lib. You are now ready for using the classes of SMPPLIB.
The SMPPCOM is the project for the COM component, it is dependent on the smpplib.dll built for the SMPPLIB project, so you may have to manually put them together. The SMPPCOM is an ATL project that supports MFC.
TestServer is only a project for me to test the sending/receiving of packets, so that I can verify the fields inside a packet after the complete encode/decode process. In TestServer, packets are processed in processPacket
routine, while in SmppLibTest, packets are processed in the registered callback processPacket
.
SMPPLIB Classes introduction
CSmppDate
It is the representation in the packets for specifying dates. It encapsulates a SYSTEMTIME
as public member and a null indicator as protected member.
void setDate(CString sd);
void setDate(SYSTEMTIME sdt);
CString toString();
CSmppDate& operator=(CSmppDate &dt);
int getLength(); void setNull();
bool isNull();
CSmppAddress
It is the representation of ESME address with type of number and numbering plan indicator.
CSmppAddress(uint32 adrton, uint32 adrnpi, CString addr);
CSmppAddress& operator=(CSmppAddress& addr);
int getLength();
void setAddrNpi(uint32 adrnpi);
void setAddrTon(uint32 adrton);
void setAddr(CString addr);
CPacketBase
It is the base class of all SMPP packets. It deals with encoding the packet headers and loading the headers. In passing parameter, usually packets are passed by casting into CPacketBase
, so for getting back the SMPP packet, they have to be cast to the respective type base on the command_id
.
All packets in the library are inherited from CPacketBase
, so they all support the following operations:
uint32 getCommandId();
It gets the command ID from the packets as defined by the SMPP specification.
uint32 getCommandStatus();
It gets the command status from the packet. Usually for SMSC response packets, a command status of 0 means no error, otherwise it indicates error condition. Detailed error code can be checked from the SMPP 3.4 Specification.
uint32 getSequenceNumber();
It gets the sequence number for the packet. Sequence number is a monotonic increasing number for request packets and response packets. A response packet should set the same sequence number as the corresponding request packet.
void setCommandId(uint32 cmid);
It sets the command ID for a packet. In most cases, user shouldn't set it by his own. Correct command ID is assigned as a packet is created. Beware, you shouldn't set command ID, it's been set based on the packet you created.
void setCommandStatus(uint32 cmst);
It sets the command status of a packet. Command status is defined in the SMPP 3.4 specification.
void setSequenceNumber(uint32 seqn);
It sets the sequence number of a packet.
SMPP packets supported in the API library
Every response packet in the SMPPLIB can be passing a command packet in the constructor, to set the sequence number of the response packet as the sequence number of the command packet.
CAlertNotification
Alert Notification Packet.
CSmppAddress getSource();
CSmppAddress getEsme();
void setSource(CSmppAddress &src);
void setEsme(CSmppAddress &esme);
CGenericNack
Generic Negative Acknowledge Packet.
CBindPacketBase
Base class for Bind packets.
CString getSystemId();
CString getPassword();
CString getSystemType();
CSmppAddress& getSourceRange();
void setSystemId(CString sid);
void setPassword(CString pwd);
void setSystemType(CString stype);
void setSourceRange(CSmppAddress &addr);
void setInterfaceVersion(uint32 iver);
CBindRespBase
Base class for Bind Response packets.
void setSystemId(CString sid);
CString getSystemId();
CBindTransmitter
Bind Transmitter Packet. Inherited from CBindPacketBase
.
CBindTransmitterResp
Bind Transmitter Response Packet. Inherited from CBindRespBase
.
CBindReceiver
Bind Receiver Packet. Inherited from CBindPacketBase
.
CBindReceiverResp
Bind Receiver Response Packet. Inherited from CBindRespBase
.
CBindTransceiver
Bind Transceiver Packet. Inherited from CBindPacketBase
.
CBindTransceiverResp
Bind Transceiver Response Packet. Inherited from CBindRespBase
.
CUnbind
Unbind Packet.
CUnbindResp
Unbind Response Packet.
CMessagePacketBase
Base class for CSubmitSM
and CDeliverSM
packets.
CString getServiceType();
CSmppAddress getSource();
CSmppAddress getDestination();
uint32 getEsmClass();
uint32 getProtocolId();
uint32 getPriorityFlag();
CSmppDate getScheduledDelivery();
CSmppDate getValidityPeriod();
uint32 getRegisteredDelivery();
uint32 getReplaceIfPresent();
uint32 getSmDefaultMsgId();
uint32 getDataCoding();
uint32 getSmLength();
void getMessage(PBYTE &msg, uint32 &nsz);
void setServiceType(CString stype);
void setSource(CSmppAddress &src);
void setDestination(CSmppAddress &dest);
void setEsmClass(uint32 esm);
void setProtocolId(uint32 pid);
void setPriorityFlag(uint32 pflag);
void setRegisteredDelivery(uint32 reg);
void setReplaceIfPresent(uint32 rip);
void setDataCoding(uint32 enc);
void setSmLength(uint32 smlen);
void setMessage(PBYTE msg, uint32 nsz);
CMessageRespBase
Base class for CSubmitSMResp
and CDeliverSMResp
.
CString getMessageId();
void setMessageId(CString msgid);
CSubmitSM
Submit Short Message Packet. Inherited from CMessagePacketBase
.
CSubmitSMResp
Submit Short Message Response Packet. Inherited from CMessageRespBase
.
CDeliverSM
Deliver Short Message Packet. Inherited from CMessagePacketBase
.
CDeliverSMResp
Deliver Short Message Response. Inherited from CMessageRespBase
.
CEnquireLink
Enquire Link Packet.
CEnquireLinkResp
Enquire Link Response.
CQuerySM
Query Short Message Packet.
CString getMessageId();
void setMessageId(CString msgid);
CQuerySMResp
Query Short Message Response Packet.
CString getMessageId();
void setMessageId(CString msgid);
CSmppDate getFinalDate();
void setFinalDate(CSmppDate &fldate);
uint32 getMessageState();
void setMessageState(uint32 msgst);
uint32 getErrorCode();
void setErrorCode(uint32 errcode);
CDataPacketBase
Base class for CDataSM
.
CString getServiceType();
CSmppAddress getSource();
CSmppAddress getDestination();
uint32 getEsmClass();
uint32 getRegisteredDelivery();
uint32 getDataCoding();
void setServiceType(CString stype);
void setSource(CSmppAddress &src);
void setDestination(CSmppAddress &dest);
void setEsmClass(uint32 esm);
void setRegisteredDelivery(uint32 reg);
void setDataCoding(uint32 enc);
CDataSM
Data Short Message Packet. Inherited from CDataPacketBase
.
CDataSMResp
Data Short Message Response Packet.
ESME entities supported:
CEsmeTransmitter
Transmitter to send SMS.
CEsmeReceiver
Receiver to receive SMS.
CEsmeTransceiver
Transceiver to send and receive SMS.
Besides bind
, unbind
, submitMessage
and enquireLink
operations of the ESME entities, packets can be sent directly through:
bool sendPacket(CPacketBase &pak);
The ESME entity classes are designed to operate in asynchronous mode. A callback routine should be prepared in the order packets are received from SMSC. This is the basic place where a client application defines its logic. To register the call back routine to the ESME entities, call the registerProcessPacket
with the callback function pointer.
The prototype of the callback function should be in the form:
void __stdcall processPacket(CPacketBase *pak, LPVOID param)
The library is dependent on MFC. Before any call, the user application must initialize the Winsock library by issuing WSAStartup()
.
Sample Code
#include "stdafx.h"
#include "SMPPAPI.h"
#include "winsock2.h"
#include "EsmeTransceiver.h"
#include "SmppUtil.h"
#include "smpppacket.h"
#include "smpp.h"
void __stdcall processPacket(CPacketBase *pak, LPVOID param)
{
switch (pak->getCommandId())
{
case SMPP_BIND_TRANSMITTER_RESP:
{
CBindTransmitterResp *pPak;
pPak = static_cast<CBindTransmitterResp *>(pak);
TRACE("Packet is casted to CBindTransmitterResp\n");
TRACE(pPak->getSystemId());
TRACE("\n");
trans.submitMessage("Hiya, this is my message",
"85261110229", 2, 0);
}
break;
case SMPP_BIND_RECEIVER_RESP:
{
CBindReceiverResp *pPak;
pPak = static_cast<CBindReceiverResp *>(pak);
TRACE("Packet is casted to CBindReceiverResp\n");
TRACE(pPak->getSystemId());
TRACE("\n");
}
break;
case SMPP_BIND_TRANSCEIVER_RESP:
{
CBindTransceiverResp *pPak;
pPak = static_cast<CBindTransceiverResp *>(pak);
TRACE("Packet is casted to CBindTransceiverResp\n");
TRACE(pPak->getSystemId());
TRACE("\n");
}
break;
case SMPP_DELIVER_SM:
{
CDeliverSM *pPak;
pPak = static_cast<CDeliverSM *>(pak);
TRACE("Packet is casted to CDeliverSM\n");
TRACE("\n");
}
break;
case SMPP_SUBMIT_SM_RESP:
{
CSubmitSMResp *pPak;
pPak = static_cast<CSubmitSMResp *>(pak);
TRACE("Packet is casted to CSubmitSMResp\n");
TRACE(pPak->getMessageId());
TRACE("\n");
trans.unbind();
}
break;
case SMPP_UNBIND_RESP:
{
CUnbindResp *pPak;
pPak = static_cast<CUnbindResp *>(pak);
TRACE("Packet is casted to CUnbindResp\n");
TRACE("\n");
}
break;
default:
break;
}
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
int nRetCode = 0;
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
CSmppAddress scr(2, 0, "85263243234");
trans.init("212.5.192.111", 5055);
trans.registerProcessPacket(processPacket, NULL);
trans.bind("t_test", "testpwd", "", scr);
getch();
}
}
In the example, a callback function processPacket(CPacketBase *pak, LPVOID param)
is prepared to handle the notifications from SMSC. To set the procedure, you've noticed that, in main
, the sample called registerProcessPacket(processPacket, NULL)
. When the SMSC replies the SMPP_BIND_TRANSCEIVER_RESP
, it displays the System ID of the remote system, and then submits a message to a mobile subscriber.
Example projects can be found in the example folders, the SmppLibTest and TestServer. To try it, just run the TestServer, then the SmppLibTest.
TestServer is a sample testing server built using the SMPPLIB, while SmppLibTest is a client application.
COM Support
With amazing COM support, several COM classes are created for the SMPPLIB. Now, you can send and receive SMS in any COM automation support language and system, including Visual Basic and ASP websites. After installation, you should have SMPPCOMLib defined in your system.
The following COM classes are created:
SmppDateCom
Method
STDMETHOD(isNull)(VARIANT_BOOL *valnull);
STDMETHOD(setNull)(void);
STDMETHOD(toString)(BSTR *strdate);
SmppAddressCom
Property
TON
NPI
Address
SubmitSMCom / DeliverSMCom
Property
ServiceType
Source
Destination
esmClass
dataCoding
protocolID
priorityFlag
scheduledDelivery
validityPeriod
registeredDelivery
replaceIfPresent
smDefaultMsgId
Message
Method
STDMETHOD(compactMessage)(void);
STDMETHOD(flipByteOrder)(void);
STDMETHOD(setMessage)(VARIANT msgdata);
STDMETHOD(getMessage)(VARIANT* pmsgdata);
EsmeTransmitterCom / EsmeReceiverCom / EsmeTransceiverCom
Method
STDMETHOD(bind)(BSTR sysid, BSTR passwd,
BSTR systype, ISmppAddressCom* iaddr, VARIANT_BOOL* pret);
STDMETHOD(unbind)(VARIANT_BOOL* pret);
STDMETHOD(enquireLink)(VARIANT_BOOL* pret);
STDMETHOD(init)(BSTR svrip, LONG port);
STDMETHOD(close)(void);
STDMETHOD(get_Connected)(VARIANT_BOOL* pVal);
In addition to the common methods, EsmeTransmitterCom
and EsmeReceiverCom
also support a submitting message method.
STDMETHOD(submitMessage)(ISubmitSMCom* isubmit, BSTR* pMsgid, VARIANT_BOOL* pret);
For EsmeTransceiverCom
and EsmeReceiver
, whenever a MO message is received, an OnDeliverSM
event will be fired. This event can be handled in an automation client.
For example, in VB.NET, it is handled by the subroutine declared with the following syntax.
Private Sub receiver_OnDeliverSM(ByVal dsm As SMPPCOMLib.DeliverSMCom) Handles receiver.OnDeliverSM
For details of their usage, please take a look to the SmppComTest project, which is a testing VB project for sending and receiving SMS messages.
In order to receive events, you should create your instance of EsmeReceiverCom
or EsmeTransceiverCom
with the WithEvent
keyword in Visual Basic.
Acknowledgement
As I remember, I've partially used code from Norm Almond, which is the Buffer
class and classes for TCP connections. Thanks.
Frequently Asked Questions
Q1: What kind of conformance with SMPP specifications v3.3 and v3.4, this library supports?
A1: This library partially supports SMPP spec v3.3 and v3.4. Here it provides a handful of tedious packet encoding and decoding methods, and put them into individual classes. Users have to just use exposing getter/setter to manipulate the packet contents instead. This library also provides some ESME entities to make connections to SMSC and the skeleton to exchange packets with SMSC.
Q2: How I use it in VB.NET, VC++.NET?
A2: This library was developed in VC6, and recompiled in VC++.NET. They are not managed classes. However, you can still use Interop Service to use COM components. If you don't want to use Interop service, you may consider to buy our commercial .NET version. It supports more than this free C++ version.
Q3: How to compile this library in VC6?
A3: For the smpplib, it comes with a VC6 project file, you just have to open it and compile it. For the SMPPCOM project, I didn't build the VC6 COM project in VS6, so you have to copy create the VC6 COM project yourself. It is quite trivial I think, you have to just create an ATL project and put the source code into the project.
Q4: What is linkListen
in CEsmeReceiver
?
A4: It listens to a port for SMSC to make connection to your receiver. This is usually for outbound packets send by SMSC to ask you to bind to them, to receive message.
Q5: What is the difference between the .NET commercial version and this free version?
A5: This free version was developed in VC++, while the commercial version is developed in C#. The commercial version offers more support on auto-reconnection, auto-enquirelink, auto deliver_sm
and enquire_link
responses, optional parameters, etc. It also comes with a featured SMS sending/receiving application with broadcast feature. Personally, I think C# is easier to use than VC++.
Q6: How do I receive delivery acknowledge?
A6: So far as I know, this needs some setup in your SMSC. Besides, in Submit SM packet, there is an attribute called Registered Delivery you can set. For details for the bit pattern you need to set, please consult the SMPP specification.
Q7: How do I start using this library within my VC++ project?
A7: Firstly, you should read thoroughly this document, and understand the sample project. This library operates in event (packet receiving) driven mode. You have to provide the callback handler for 'what is going to be done when a packet is received'.
Q8: Why couldn't my client create the COM components, but in my development platform it works fine?
A8: The COM project is just a wrapper to the smpplib.dll. You should put SmppCom.dll and Smpplib.dll together. If you did file copy to your client computer, you have to use 'regsrv32 SmppCom.dll' to register the COM into your client machine.
Q9: Does it support Optional Parameter?
A9: Currently, optional parameters are not supported in this C++ version, and I am not going to spend time to support them.
Q10: Can I use it to send free SMS?
A10: This packet library is used for connecting to an SMSC. It is not for sending SMS directly. Whether SMS is charged, it is up to the Telecommunication companies, but mostly they will charge. This library is not intended to be used by hobbyists, though you can still study it.