Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

An SMPPLIB with COM Support

0.00/5 (No votes)
27 Oct 2003 6  
It is an SMPP implementation of v3.3 and v3.4 ( partial support). You can use it to connect to SMSC and send/receive SMS.

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);

//setter

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;

    // initialize MFC and print and error on failure

    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: change error code to suit your needs

        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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here