Skip to content

Commit

Permalink
checking session type when handling submit_sm and sending MO message
Browse files Browse the repository at this point in the history
  • Loading branch information
ukarim committed Jul 11, 2023
1 parent 6d9ad8a commit 5c2f188
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 39 deletions.
57 changes: 35 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,52 @@

Lightweight, zero-dependency and stupid SMSc simulator.

### Warning

* simulator implements only a small subset of the SMPP3.4 specification and supports only the following PDUs:
- `bind_transmitter`, `bind_receiver`, `bind_transceiver`
- `unbind`
- `submit_sm`
- `enquire_link`
- `deliver_sm_resp`
* simulator does not perform PDU validation

### Usage

```bash
> go build
> ./smscsim
1) Build from sources (need golang compiler)

```
go build
./smscsim
```

2) Build docker image

This will start smpp server on port _2775_ and web server on port _12775_.
```
docker build -t smscsim .
docker run -p 2775:2775 -p 12775:12775 smscsim
```

or
3) Use prebuild docker image (from hub.docker.com)

```bash
> docker run -p 2775:2775 -p 12775:12775 ukarim/smscsim
```
docker run -p 2775:2775 -p 12775:12775 ukarim/smscsim
```

then, just configure your smpp client to connect to `localhost:2775`

### Features

### Delivery reports
#### Delivery reports (DLR)

If it was requested by _submit_sm_ packet, delivery receipt will be returned after 2 sec with a message state always set to _DELIVERED_.
If it was requested by _submit_sm_ packet, delivery receipt will be returned
after 2 sec with a message state always set to _DELIVERED_.

### MO messages
#### MO messages

Mobile originated messages (from `smsc` to `smpp client`) can be sent using
special web page available at `http://localhost:12775` . MO message will be
delivered to the selected smpp session using a _deliver_sm_ PDU.

### Warning

MO messages can be triggered using a special web page http://localhost:12775.
MO message will be delivered to the selected smpp session using a _deliver_sm_ PDU.
* simulator implements only a small subset of the SMPP3.4 specification and supports only the following PDUs:
- `bind_transmitter`, `bind_receiver`, `bind_transceiver`
- `unbind`
- `submit_sm`
- `enquire_link`
- `deliver_sm_resp`
* simulator does not perform PDU validation

### Env variables

Expand Down
51 changes: 34 additions & 17 deletions smsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
const (
STS_OK = 0x00000000
STS_INVALID_CMD = 0x00000003
STS_INV_BIND_STS = 0x00000004
STS_ALREADY_BOUND = 0x00000005
)

Expand All @@ -43,8 +44,9 @@ const (
)

type Session struct {
SystemId string
Conn net.Conn
SystemId string
Conn net.Conn
ReceiveMo bool
}

type Tlv struct {
Expand Down Expand Up @@ -93,9 +95,11 @@ func (smsc *Smsc) BoundSystemIds() []string {

func (smsc *Smsc) SendMoMessage(sender, recipient, message, systemId string) error {
var conn net.Conn
receiveMo := false
for _, sess := range smsc.Sessions {
if systemId == sess.SystemId {
conn = sess.Conn
receiveMo = sess.ReceiveMo
}
}

Expand All @@ -104,6 +108,11 @@ func (smsc *Smsc) SendMoMessage(sender, recipient, message, systemId string) err
return fmt.Errorf("No session found for systemId: [%s]", systemId)
}

if !receiveMo {
log.Printf("Cannot send MO message to systemId: [%s]. Only RECEIVER and TRANSCEIVER sessions could receive MO messages", systemId)
return fmt.Errorf("Only RECEIVER and TRANSCEIVER sessions could receive MO messages")
}

// TODO implement UDH for large messages
shortMsg := truncateString(message, 70) // just truncate to 70 symbols
var tlvs []Tlv
Expand All @@ -123,6 +132,7 @@ func handleSmppConnection(smsc *Smsc, conn net.Conn) {
sessionId := rand.Int()
systemId := "anonymous"
bound := false
receiver := false

defer delete(smsc.Sessions, sessionId)
defer conn.Close()
Expand Down Expand Up @@ -165,9 +175,11 @@ func handleSmppConnection(smsc *Smsc, conn net.Conn) {
respBytes = headerPDU(respCmdId, STS_ALREADY_BOUND, seqNum)
log.Printf("[%s] already has bound session", systemId)
} else {
smsc.Sessions[sessionId] = Session{systemId, conn}
receiveMo := cmdId == BIND_RECEIVER || cmdId == BIND_TRANSCEIVER
smsc.Sessions[sessionId] = Session{systemId, conn, receiveMo}
respBytes = stringBodyPDU(respCmdId, STS_OK, seqNum, "smscsim")
bound = true
receiver = cmdId == BIND_RECEIVER
}
}
case UNBIND: // unbind request
Expand Down Expand Up @@ -236,20 +248,25 @@ func handleSmppConnection(smsc *Smsc, conn net.Conn) {

// prepare submit_sm_resp
msgId := strconv.Itoa(rand.Int())
respBytes = stringBodyPDU(SUBMIT_SM_RESP, STS_OK, seqNum, msgId)

if registeredDlr != 0 {
go func() {
time.Sleep(2000 * time.Millisecond)
now := time.Now()
dlr := deliveryReceiptPDU(msgId, now, now)
if _, err := conn.Write(dlr); err != nil {
log.Printf("error sending delivery receipt to system_id[%s] due %v.", systemId, err)
return
} else {
log.Printf("delivery receipt for message [%s] was send to system_id[%s]", msgId, systemId)
}
}()

if receiver {
respBytes = headerPDU(SUBMIT_SM_RESP, STS_INV_BIND_STS, seqNum)
} else {
respBytes = stringBodyPDU(SUBMIT_SM_RESP, STS_OK, seqNum, msgId)

if registeredDlr != 0 {
go func() {
time.Sleep(2000 * time.Millisecond)
now := time.Now()
dlr := deliveryReceiptPDU(msgId, now, now)
if _, err := conn.Write(dlr); err != nil {
log.Printf("error sending delivery receipt to system_id[%s] due %v.", systemId, err)
return
} else {
log.Printf("delivery receipt for message [%s] was send to system_id[%s]", msgId, systemId)
}
}()
}
}
}
case DELIVER_SM_RESP: // deliver_sm_resp
Expand Down

0 comments on commit 5c2f188

Please sign in to comment.