SMPP 3.4 Protocol for the Go programming language

SMPP 3.4

GoDoc Go Report Card Build Status

This is an implementation of SMPP 3.4 for Go, based on the original smpp34 from Kevin Patel.

The API has been refactored to idiomatic Go code with more tests and documentation. There are also quite a few new features, such as a test server (see smpptest package) and support for text transformation for LATIN-1 and UCS-2.

It is not fully compliant, there are some TODOs in the code.

Usage

Following is an SMPP client transmitter wrapped by an HTTP server that can send Short Messages (SMS):

func main() {
    // make persistent connection
    tx := &smpp.Transmitter{
        Addr:   "localhost:2775",
        User:   "foobar",
        Passwd: "secret",
    }
    conn := tx.Bind()
    // check initial connection status
    var status smpp.ConnStatus
    if status = <-conn; status.Error() != nil {
        log.Fatalln("Unable to connect, aborting:", status.Error())
    }
    log.Println("Connection completed, status:", status.Status().String())
    // example of connection checker goroutine
    go func() {
        for c := range conn {
            log.Println("SMPP connection status:", c.Status())
        }
    }()
    // example of sender handler func
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        sm, err := tx.Submit(&smpp.ShortMessage{
            Src:      r.FormValue("src"),
            Dst:      r.FormValue("dst"),
            Text:     pdutext.Raw(r.FormValue("text")),
            Register: pdufield.NoDeliveryReceipt,
            TLVFields: pdutlv.Fields{
                pdutlv.TagReceiptedMessageID: pdutlv.CString(r.FormValue("msgId")),
            },
        })
        if err == smpp.ErrNotConnected {
            http.Error(w, "Oops.", http.StatusServiceUnavailable)
            return
        }
        if err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
        io.WriteString(w, sm.RespID())
    })
    log.Fatal(http.ListenAndServe(":8080", nil))
}

You can test from the command line:

curl localhost:8080 -X GET -F src=bart -F dst=lisa -F text=hello

If you don't have an SMPP server to test, check out Selenium SMPPSim. It has been used for the development of this package.

Tools

See the tools under cmd/. There's a command line tool for sending SMS from the command line, and an HTTP server with WebSocket support.

Supported PDUs

  • bind_transmitter
  • bind_transmitter_resp
  • bind_receiver
  • bind_receiver_resp
  • bind_transceiver
  • bind_transceiver_resp
  • outbind
  • unbind
  • unbind_resp
  • submit_sm
  • submit_sm_resp
  • submit_sm_multi
  • submit_sm_multi_resp
  • data_sm
  • data_sm_resp
  • deliver_sm
  • deliver_sm_resp
  • query_sm
  • query_sm_resp
  • cancel_sm
  • cancel_sm_resp
  • replace_sm
  • replace_sm_resp
  • enquire_link
  • enquire_link_resp
  • alert_notification
  • generic_nack
  • tag-length-value (TLV)

Copyright

See LICENSE and AUTHORS files for details.

Owner
Comments
  • Receive message handler is not working

    Receive message handler is not working

    Hi,

    With the latest version sms receive event is not firing and status is changing continuously connected and disconnects. Message send successfully but received message event is not firing. When using Transmitter in place of Transceiver without handler then status connected for all time. Using below code .

       f := func(p pdu.Body) {
    	switch p.Header().ID {
    	case pdu.DeliverSMID:
    		f := p.Fields()
    		src := f[pdufield.SourceAddr]
    		dst := f[pdufield.DestinationAddr]
    		txt := f[pdufield.ShortMessage]
    		log.Printf("Short message from=%q to=%q: %q",
    			src, dst, txt)
    	}
    }
    
    tx := &smpp.Transceiver{
    	Addr:   "192.168.0.103:8802",
    	User:   "userid",
    	Passwd: "password",
    	Handler:     f,  // Handle incoming SM or delivery receipts.
    }
    // Create persistent connection, wait for the first status.
    conn := <-tx.Bind()
    if conn.Status() != smpp.Connected {
    	log.Fatal(conn.Error())
    }
    sm, err := tx.Submit(&smpp.ShortMessage{
    	Src:      "src",
    	Dst:      "des",
    	Text:     pdutext.Raw("sandeep"),
    	Register: pdufield.NoDeliveryReceipt,
    })
    if err != nil {
    	log.Fatal(err)
    }
    log.Println("Message ID:", sm.RespID())
    
    
    for{
    	
    	time.Sleep(time.Millisecond * 1600)
    }
    
  • Windowed mode & automatic reconnection

    Windowed mode & automatic reconnection

    1. Does this library allows to send submit_sm messages with a window size greater than 1? For example, if the output window size is set to 10, I am allowed to send up to 10 submit_sm pdus before having the submit_sm_resp received. This mode can increase throughput to smsc substantially.
    2. What about automatic reconnection of dropped smpp connections to smsc?

    Many thanks!

  • features and fixes

    features and fixes

    1. RateLimiter from dev tree
    2. Fixed QuerySM "0" status according to SMPP 5.0 specs (props to @blind-oracle)
    3. Use BindInterval delay (if given) for retry in Bind() instead of exponential growth (props to @blind-oracle)
    4. Implemented EnquireLinkResp as time of the last response in enquireLink function:
    • if we don't get the response from server within the time window, unbind and close the connection (according to specs, enquirelink serves as "confidence-check of the communication path between an ESME and an SMSC", so if there's no response, we can't be confident that our connection is alive)
    1. Added src TON/NPI to QuerySM (props to @blind-oracle)
    2. Added EnquireLinkTimeout (props to @blind-oracle)
    3. Renamed conn to cl as it holds the client, not the connection
    4. Added sending of DeliverSMResp to receiver (props to @blind-oracle)
    • this fixes the problem when we're not responding to the receiver gate and it stops the connection from the server side
    1. Merged pull request https://github.com/fiorix/go-smpp/pull/28
  • Support messages larger than characters allowed per sms

    Support messages larger than characters allowed per sms

    I tried sending larger than one sms content UCS (60+) and Latin(160+) encoded data using ShortMessage struct but it failed on smpp service provided by cellular network. Sending large latin encoded messages work on smppsim. Smppsim fails to process any ucs encoded messages. I read up on it and came across these at http://www.activexperts.com/sms-component/smpp-specifications/smpp-parameter-definition/ :

    short_message

    The short_message parameter contains the user data. A maximum of 254 octets can be sent. ESME's should use the optional message_payload parameter in submit_sm, submit_multi, and deliver_sm to send larger user data sizes.

    sm_length

    The sm_length parameter specifies the length of the short_message parameter in octets. The sm_length should be set to 0 in the submit_sm, submit_multi, and deliver_sm PDUs if the message_payload parameter is being used to send user data larger than 254 octets.

    If above is right, can this library support sending larger than 160 chars messages? I couldn't find any logic to handle this in code.

  • Initial implementation of submit_multi PDU

    Initial implementation of submit_multi PDU

    Tested with SMPPSim simulator, tried to not change the API much to avoid more repetition, so SM can optionally hold submit multi parameters, but any improvement suggestions welcome. Once approach is validate I'll add more code to validate size of addresses and distribution lists as per SMPP spec.

  • Support 2 byte reference number in UDH header

    Support 2 byte reference number in UDH header

    Hey there,

    We're going to be running some services with this library that are going to be using a fairly large number of binds. With the current 1 byte reference number the chance of a collision would be relatively high and we'd like to use the alternative header with the 2 byte number. For now we've patched the library to add it in but was wanting to ask if you would accept a PR for it?

    Cheers, Lucian

  • short_message in DeliverSM scrambles when data_coding is 0x08

    short_message in DeliverSM scrambles when data_coding is 0x08

    When receiving DeliverSM of a UCS encoded message, short_message gets decoded using UCS2 and gets corrupt. A solution is, not to decode short_message when decoding PDU and let user decide what to do.

    Current output of short_message pdu field: selection_078

    After I removed automatic decoding: selection_079

  • Problems using test server

    Problems using test server

    Hi,

    I am trying to use (and expand) the server in smpptest. I ran a server and took the sample code for running a client. When I try to submit a ShortMessage with transmitter.Submit(), I get the error unexpected PDU ID: SubmitSM which makes sense since the server is only responding back with the same PDU in the EchoHandler.

    In the EchoHandler, I modified the ID of the PDU to be SubmitSMRespID by accessing the headers of the request PDU and when I send it back, the client times out. I pinpointed the problem to be in list.go:112 where it complains: not enough data for tag 0x0: want 29554, have 22.

    I would imagine that messing directly with the headers could be a bad idea, so I went ahead and used the function NewSubmitSMResp() from types.go to build a the appropriate response in the EchoHandler. When I sent it back, the client just times out again with no response and I can't pinpoint the cause.

    EchoHandler looks like this:

    func EchoHandler(conn Conn, m pdu.Body) {
        // Approach #1: Send it back as-is
    
        // Approach #2: Modify the ID directly
        // m.Header().ID = pdu.SubmitSMRespID
    
        // Approach #3: Send a new response
        // m = pdu.NewSubmitSMResp()
    
        err := conn.Write(m)
        if err != nil {
            fmt.Println(err)
        }
    }
    

    What am I doing wrong? Or am I missing to implement something? I am quite knew to SMPP so bare with me if there are obvious mistakes I didn't spot.

    Thanks!

  • Method for sending additional fields with SMS

    Method for sending additional fields with SMS

    Firstly, thanks for really awesome work. I have used and tested this package for simple sms and it works on smppsim simulator. My real smpp provided wants addrton,dest_addr_ton, source_addr_npi and addr_npi to be provided. If I send sms without these fields using Submit method it says invalid source address.

    Method func (t *Transmitter) Submit(sm *ShortMessage) (*ShortMessage, error) doesn't support a parmeter to send additional fields along with simple ones. May I suggest a new method with signature:

    func (t *Transmitter) SubmitWithFields(sm *ShortMessage, fields map[string]interface{}) (*ShortMessage, error)

    I tried implementing above using following code:

    
    // SubmitWithFields sends a short message along with extra pdu fields and returns and updates the given
    // sm with the response status. It returns the same sm object.
    func (t *Transmitter) SubmitWithFields(sm *ShortMessage, fields map[string]int) (*ShortMessage, error) {
        p := pdu.NewSubmitSM()
        f := p.Fields()
        f.Set(pdufield.SourceAddr, sm.Src)
        f.Set(pdufield.DestinationAddr, sm.Dst)
        f.Set(pdufield.ShortMessage, sm.Text)
        f.Set(pdufield.RegisteredDelivery, uint8(sm.Register))
        for k, v := range fields {
            err := f.Set(pdufield.Name(k), v)
            if err != nil {
                return sm, fmt.Errorf("Couldn't set field %s with value %s. Error: %s", k, v, err)
            }
        }
        // Check if the message has validity set.
        if sm.Validity != time.Duration(0) {
            f.Set(pdufield.ValidityPeriod, convertValidity(sm.Validity))
        }
        resp, err := t.do(p)
        if err != nil {
            return nil, err
        }
        sm.resp.Lock()
        sm.resp.p = resp.PDU
        sm.resp.Unlock()
        if id := resp.PDU.Header().ID; id != pdu.SubmitSMRespID {
            return sm, fmt.Errorf("unexpected PDU ID: %s", id)
        }
        if s := resp.PDU.Header().Status; s != 0 {
            return sm, s
        }
        return sm, resp.Err
    }
    

    but when I submit with this method, smppsim disconnects and times out. Is there any better way via which I can send additional fields?

  • ошибка подключения SMPP

    ошибка подключения SMPP

    Можете подсказать делаю пакет для API своего https://play.golang.org/p/ES7Fv1tuzJz . Но ошибка идетъ err con 2018/02/06 17:49:59 SMPP connection status: Connected err con 2018/02/06 17:50:33 SMPP connection status: Connected err con 2018/02/06 17:51:22 SMPP connection status: Connected

    в связи с чем такая ошибка может возникать

  • GSM7 encoding

    GSM7 encoding

    Hi all,

    Currently there is no support for GSM7 encoding or packing. Since most SMPP providers do not support receiving GSM7 packed (septet to octet conversion) requests, I suggest that we add two new codecs:

    GSM7 Packed

    Encode and pack messages. That means messages should be split after 140-7 bytes (UDH header), since there is the potential for splitting an escaped character (which consists of two bytes) like { across two parts, we should limit each part to 140-7-1 bytes.

    GSM7 Unpacked

    Only encode message, since many SMPP providers will not accept GSM7 packed. That means message should be split after 160-7 bytes (UDH header), since there is the potential for splitting an escaped character (which consists of two bytes) like { across two parts, we should limit each part to 160-7-1 bytes.

  • Concatenated / Multipart

    Concatenated / Multipart

    hello i'm read https://www.openmarket.com/docs/Content/apis/v3smpp/smpp-multipart-messages.htm so need to change udhheader from

        UDHHeader := make([]byte, 7)
    UDHHeader[0] = 0x06              // length of user data header
    UDHHeader[1] = 0x08              // information element identifier, CSMS 16 bit reference number
    UDHHeader[2] = 0x04              // length of remaining header
    UDHHeader[3] = uint8(rn >> 8)    // most significant byte of the reference number
    UDHHeader[4] = uint8(rn)         // least significant byte of the reference number
    UDHHeader[5] = uint8(countParts) // total number of message parts
    

    to UDHHeader := make([]byte, 7) UDHHeader[0] = 0x05 // Length of the rest of the UDH. This is "5" bytes. UDHHeader[1] = 0x00 //Indicates it is a multipart message. UDHHeader[2] = 0x03 // Length of the subheader; e.g., the rest of the UDH. This is "3" bytes. UDHHeader[3] = uint8(rn >> 8) // Total number of parts in the multipart message. UDHHeader[4] = uint8(countParts) // total number of message parts

    can you help how i can do it?

  • [encoding/gsm7] Fix the bug of confusion with '@' when the first 7 bi…

    [encoding/gsm7] Fix the bug of confusion with '@' when the first 7 bi…

    Fix the bug of confusion with '@' when the first 7 bits of the last byte after GSM7(Packed) pack are all 0.

    Change-Id: I87dca3d5b1b21c1d722e630b8cb5228c57d5084e

  • Use GSM(packed) to encode and then decode, there is an extra '@' character

    Use GSM(packed) to encode and then decode, there is an extra '@' character

    Question

    GSM7 (Packed), encode first, and then decode the encoded result, which is inconsistent with the original input, and there are more '@' characters

    For example

    My source input was

    "1234567890abcdefghijklm"
    

    Firstly I encoded it to a bytes slice m

    m := []byte{49,217,140,86,179,221,112,57,88,88,60,38,151,205,103,116,90,189,102,183,1}
    

    Then I Decoded the m, but got

    "1234567890abcdefghijklm@"
    

    There was one more character '@' than the original input.

    image

    Here is my test codes:

    func TestEncode(t *testing.T) {
    	content := "1234567890abcdefghijklm"
    	t.Logf("original content: %s, length: %d", strconv.Quote(content), len(content))
    
    	// encode the content with packed option
    	encoder := GSM7(true).NewEncoder()
    	es, _, err := transform.Bytes(encoder, []byte(content))
    	assert.Nil(t, err)
    	t.Logf("after encoded. bytes: %v, length: %d", es, len(es))
    
    	// decode `es`
    	decoder := GSM7(true).NewDecoder()
    	res, _, err := transform.Bytes(decoder, es)
    	assert.Nil(t, err)
    	t.Logf("after decode. content: %s, length: %d", strconv.Quote(string(res)), len(res))
    }
    
  • Converting the hex in text field of delivery receipt to original UCS2 text submitted

    Converting the hex in text field of delivery receipt to original UCS2 text submitted

    I am sending non-English (Chinese) string via UCS2 to SMPP and in the delivery receipt receive a hex in text part, which otherwise in normal gsm comes as first 10 characters of the message sent

    How do I convert hex in case of UCS2 into the Chinese string ?

    I assumed it as hex and tried but it is not working. Can we initialize pdutext and then execute its function to get the conversion ?

  • [BUG] - message encoding not working for long unicode message

    [BUG] - message encoding not working for long unicode message

    I'm trying to send unicode sms with more than 70 characters using SubmitLongMsg. But the message received has wrong encoding and showing chinese like text.

Related tags
wire protocol for multiplexing connections or streams into a single connection, based on a subset of the SSH Connection Protocol

qmux qmux is a wire protocol for multiplexing connections or streams into a single connection. It is based on the SSH Connection Protocol, which is th

Dec 26, 2022
A simple tool to convert socket5 proxy protocol to http proxy protocol

Socket5 to HTTP 这是一个超简单的 Socket5 代理转换成 HTTP 代理的小工具。 如何安装? Golang 用户 # Required Go 1.17+ go install github.com/mritd/s2h@master Docker 用户 docker pull m

Jan 2, 2023
A Language Server Protocol (LSP) server for Jsonnet

Jsonnet Language Server Warning: This project is in active development and is likely very buggy. A Language Server Protocol (LSP) server for Jsonnet.

Nov 22, 2022
Implementation of Pinocchio Protocol in Go language

pinocchio-protocol-zksnarks Implementation of Pinocchio Protocol in Go language 1 零知识证明和zksnarks 1.1 为什么需要可证明的计算? 随着技术的发展,计算能力表现出不对称的特性,例如云计算等拥有大量的算力,

Nov 3, 2021
language server protocol sdk implement for go

LSP(language server protocol) defines for golang lsp types is from vscode-languageserver-node. Project is working in progress. Example func main() {

Dec 17, 2022
Txt-lsp - A toy project with Language Server Protocol (LSP)

txt-lsp txt-lsp is a toy project where I play around with Language Server Protoc

Jan 22, 2022
BGP implemented in the Go Programming Language

GoBGP: BGP implementation in Go GoBGP is an open source BGP implementation designed from scratch for modern environment and implemented in a modern pr

Dec 31, 2022
A simple wrapper around libpcap for the Go programming language

PCAP This is a simple wrapper around libpcap for Go. Originally written by Andreas Krennmair [email protected] and only minorly touched up by Mark Smith

Dec 5, 2022
Basic LDAP v3 functionality for the GO programming language.

Basic LDAP v3 functionality for the GO programming language. Install For the latest version use: go get gopkg.in/ldap.v2 Import the latest version wi

May 24, 2022
Go-web-dev - Web Development With Google's Golang Programming Language Code Snippet and Exercises.

Web Development With Google's Golang Programming Language Code Snippet and Exercises This repository contains my code snippets, hands on exercises and

Jan 16, 2022
Package arp implements the ARP protocol, as described in RFC 826. MIT Licensed.

arp Package arp implements the ARP protocol, as described in RFC 826. MIT Licensed. Portions of this code are taken from the Go standard library. The

Dec 20, 2022
Gmqtt is a flexible, high-performance MQTT broker library that fully implements the MQTT protocol V3.1.1 and V5 in golang

中文文档 Gmqtt News: MQTT V5 is now supported. But due to those new features in v5, there area lots of breaking changes. If you have any migration problem

Jan 5, 2023
A TCP Server Framework with graceful shutdown, custom protocol.

xtcp A TCP Server Framework with graceful shutdown,custom protocol. Usage Define your protocol format: Before create server and client, you need defin

Dec 7, 2022
Go library for writing standalone Map/Reduce jobs or for use with Hadoop's streaming protocol

dmrgo is a Go library for writing map/reduce jobs. It can be used with Hadoop's streaming protocol, but also includes a standalone map/reduce impleme

Nov 27, 2022
Implementation of the FTPS protocol for Golang.

FTPS Implementation for Go Information This implementation does not implement the full FTP/FTPS specification. Only a small subset. I have not done a

Mar 14, 2022
network multiplexing and framing protocol for RPC

TChannel Network multiplexing and framing protocol for RPC Read the Docs Languages: Node.js, Python, Go, Java Questions: Open a Github issue Uber's OS

Nov 26, 2022
Inspired by go-socks5,This package provides full functionality of socks5 protocol.
Inspired by go-socks5,This package provides full functionality of socks5 protocol.

The protocol described here is designed to provide a framework for client-server applications in both the TCP and UDP domains to conveniently and securely use the services of a network firewall.

Dec 16, 2022
A new way of working with Protocol Buffers.

Buf All documentation is hosted at https://buf.build. Please head over there for more details. Goal Buf’s long-term goal is to enable schema-driven de

Jan 1, 2023