Пример #1
0
// SubmitLongMsg sends a long message (more than 140 bytes)
// and returns and updates the given sm with the response status.
// It returns the same sm object.
func (t *Transmitter) SubmitLongMsg(sm *ShortMessage) (*ShortMessage, error) {
	maxLen := 134 // 140-6 (UDH)
	rawMsg := sm.Text.Encode()
	countParts := int((len(rawMsg)-1)/maxLen) + 1

	ri := uint8(t.r.Intn(128))
	UDHHeader := make([]byte, 6)
	UDHHeader[0] = 5
	UDHHeader[1] = 0
	UDHHeader[2] = 3
	UDHHeader[3] = ri
	UDHHeader[4] = uint8(countParts)
	for i := 0; i < countParts; i++ {
		UDHHeader[5] = uint8(i + 1)
		p := pdu.NewSubmitSM()
		f := p.Fields()
		f.Set(pdufield.SourceAddr, sm.Src)
		f.Set(pdufield.DestinationAddr, sm.Dst)
		if i != countParts-1 {
			f.Set(pdufield.ShortMessage, pdutext.Raw(append(UDHHeader, rawMsg[i*maxLen:(i+1)*maxLen]...)))
		} else {
			f.Set(pdufield.ShortMessage, pdutext.Raw(append(UDHHeader, rawMsg[i*maxLen:]...)))
		}
		f.Set(pdufield.RegisteredDelivery, uint8(sm.Register))
		if sm.Validity != time.Duration(0) {
			f.Set(pdufield.ValidityPeriod, convertValidity(sm.Validity))
		}
		f.Set(pdufield.ServiceType, sm.ServiceType)
		f.Set(pdufield.SourceAddrTON, sm.SourceAddrTON)
		f.Set(pdufield.SourceAddrNPI, sm.SourceAddrNPI)
		f.Set(pdufield.DestAddrTON, sm.DestAddrTON)
		f.Set(pdufield.DestAddrNPI, sm.DestAddrNPI)
		f.Set(pdufield.ESMClass, 0x40)
		f.Set(pdufield.ProtocolID, sm.ProtocolID)
		f.Set(pdufield.PriorityFlag, sm.PriorityFlag)
		f.Set(pdufield.ScheduleDeliveryTime, sm.ScheduleDeliveryTime)
		f.Set(pdufield.ReplaceIfPresentFlag, sm.ReplaceIfPresentFlag)
		f.Set(pdufield.SMDefaultMsgID, sm.SMDefaultMsgID)
		f.Set(pdufield.DataCoding, uint8(sm.Text.Type()))
		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
		}
		if resp.Err != nil {
			return sm, resp.Err
		}
	}
	return sm, nil
}
Пример #2
0
func TestShortMessageWindowSize(t *testing.T) {
	s := smpptest.NewUnstartedServer()
	s.Handler = func(c smpptest.Conn, p pdu.Body) {
		time.Sleep(200 * time.Millisecond)
		r := pdu.NewSubmitSMResp()
		r.Header().Seq = p.Header().Seq
		r.Fields().Set(pdufield.MessageID, "foobar")
		c.Write(r)
	}
	s.Start()
	defer s.Close()
	tx := &Transmitter{
		Addr:        s.Addr(),
		User:        smpptest.DefaultUser,
		Passwd:      smpptest.DefaultPasswd,
		WindowSize:  2,
		RespTimeout: time.Second,
	}
	defer tx.Close()
	conn := <-tx.Bind()
	switch conn.Status() {
	case Connected:
	default:
		t.Fatal(conn.Error())
	}
	msgc := make(chan *ShortMessage, 3)
	defer close(msgc)
	errc := make(chan error, 3)
	for i := 0; i < 3; i++ {
		go func(msgc chan *ShortMessage, errc chan error) {
			m := <-msgc
			if m == nil {
				return
			}
			_, err := tx.Submit(m)
			errc <- err
		}(msgc, errc)
		msgc <- &ShortMessage{
			Src:      "root",
			Dst:      "foobar",
			Text:     pdutext.Raw("Lorem ipsum"),
			Validity: 10 * time.Minute,
			Register: NoDeliveryReceipt,
		}
	}
	nerr := 0
	for i := 0; i < 3; i++ {
		if <-errc == ErrMaxWindowSize {
			nerr++
		}
	}
	if nerr != 1 {
		t.Fatalf("unexpected # of errors. want 1, have %d", nerr)
	}
}
Пример #3
0
func TestLongMessage(t *testing.T) {
	s := smpptest.NewUnstartedServer()
	s.Handler = func(c smpptest.Conn, p pdu.Body) {
		switch p.Header().ID {
		case pdu.SubmitSMID:
			r := pdu.NewSubmitSMResp()
			r.Header().Seq = p.Header().Seq
			r.Fields().Set(pdufield.MessageID, "foobar")
			c.Write(r)
		default:
			smpptest.EchoHandler(c, p)
		}
	}
	s.Start()
	defer s.Close()
	tx := &Transmitter{
		Addr:   s.Addr(),
		User:   smpptest.DefaultUser,
		Passwd: smpptest.DefaultPasswd,
	}
	defer tx.Close()
	conn := <-tx.Bind()
	switch conn.Status() {
	case Connected:
	default:
		t.Fatal(conn.Error())
	}
	sm, err := tx.SubmitLongMsg(&ShortMessage{
		Src:      "root",
		Dst:      "foobar",
		Text:     pdutext.Raw("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam consequat nisl enim, vel finibus neque aliquet sit amet. Interdum et malesuada fames ac ante ipsum primis in faucibus."),
		Validity: 10 * time.Minute,
		Register: NoDeliveryReceipt,
	})
	if err != nil {
		t.Fatal(err)
	}
	msgid := sm.RespID()
	if msgid == "" {
		t.Fatalf("pdu does not contain msgid: %#v", sm.Resp())
	}
	if msgid != "foobar" {
		t.Fatalf("unexpected msgid: want foobar, have %q", msgid)
	}
}
Пример #4
0
func TestShortMessage(t *testing.T) {
	s := smpptest.NewUnstartedServer()
	s.Handler = func(c smpptest.Conn, p pdu.Body) {
		switch p.Header().ID {
		case pdu.SubmitSMID:
			r := pdu.NewSubmitSMResp()
			r.Header().Seq = p.Header().Seq
			r.Fields().Set(pdufield.MessageID, "foobar")
			c.Write(r)
		default:
			smpptest.EchoHandler(c, p)
		}
	}
	s.Start()
	defer s.Close()
	tx := &Transmitter{
		Addr:   s.Addr(),
		User:   smpptest.DefaultUser,
		Passwd: smpptest.DefaultPasswd,
	}
	defer tx.Close()
	conn := <-tx.Bind()
	switch conn.Status() {
	case Connected:
	default:
		t.Fatal(conn.Error())
	}
	sm, err := tx.Submit(&ShortMessage{
		Src:      "root",
		Dst:      "foobar",
		Text:     pdutext.Raw("Lorem ipsum"),
		Register: NoDeliveryReceipt,
	})
	if err != nil {
		t.Fatal(err)
	}
	msgid := sm.RespID()
	if msgid == "" {
		t.Fatalf("pdu does not contain msgid: %#v", sm.Resp())
	}
	if msgid != "foobar" {
		t.Fatalf("unexpected msgid: want foobar, have %q", msgid)
	}
}
Пример #5
0
func ExampleTransceiver() {
	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:    "localhost:2775",
		User:    "******",
		Passwd:  "secret",
		Handler: f,
	}
	conn := tx.Bind() // make persistent connection.
	go func() {
		for c := range conn {
			log.Println("SMPP connection status:", c.Status())
		}
	}()
	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: smpp.FinalDeliveryReceipt,
		})
		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))
}
Пример #6
0
func TestNotConnected(t *testing.T) {
	s := smpptest.NewUnstartedServer()
	s.Handler = func(c smpptest.Conn, p pdu.Body) {
		switch p.Header().ID {
		case pdu.SubmitSMID:
			r := pdu.NewSubmitSMResp()
			r.Header().Seq = p.Header().Seq
			r.Fields().Set(pdufield.MessageID, "foobar")
			c.Write(r)
		default:
			smpptest.EchoHandler(c, p)
		}
	}
	s.Start()
	defer s.Close()
	tx := &Transmitter{
		Addr:   s.Addr(),
		User:   smpptest.DefaultUser,
		Passwd: smpptest.DefaultPasswd,
	}
	// Open connection and then close it
	conn := <-tx.Bind()
	switch conn.Status() {
	case Connected:
	default:
		t.Fatal(conn.Error())
	}
	tx.Close()
	_, err := tx.Submit(&ShortMessage{
		Src:      "root",
		Dst:      "foobar",
		Text:     pdutext.Raw("Lorem ipsum"),
		Validity: 10 * time.Minute,
		Register: NoDeliveryReceipt,
	})
	if err != ErrNotConnected {
		t.Fatalf("Error should be not connect, got %s", err.Error())
	}

}
Пример #7
0
func (rpc *SM) submit(req url.Values) (resp *ShortMessageResp, status int, err error) {
	sm := &smpp.ShortMessage{}
	var msg, enc, register string
	f := form{
		{"src", "number of sender", false, nil, &sm.Src},
		{"dst", "number of recipient", true, nil, &sm.Dst},
		{"text", "text message", true, nil, &msg},
		{"enc", "text encoding", false, []string{"latin1", "ucs2"}, &enc},
		{"register", "registered delivery", false, []string{"final", "failure"}, &register},
	}
	if err := f.Validate(req); err != nil {
		return nil, http.StatusBadRequest, err
	}
	switch enc {
	case "":
		sm.Text = pdutext.Raw(msg)
	case "latin1", "latin-1":
		sm.Text = pdutext.Latin1(msg)
	case "ucs2", "ucs-2":
		sm.Text = pdutext.UCS2(msg)
	}
	switch register {
	case "final":
		sm.Register = smpp.FinalDeliveryReceipt
	case "failure":
		sm.Register = smpp.FailureDeliveryReceipt
	}
	sm, err = rpc.tx.Submit(sm)
	if err == smpp.ErrNotConnected {
		return nil, http.StatusServiceUnavailable, err
	}
	if err != nil {
		return nil, http.StatusBadGateway, err
	}
	resp = &ShortMessageResp{MessageID: sm.RespID()}
	return resp, http.StatusOK, nil
}
Пример #8
0
		sender := c.Args()[0]
		recipient := c.Args()[1]
		text := strings.Join(c.Args()[2:], " ")
		log.Printf("Command: send %q %q %q", sender, recipient, text)
		var register smpp.DeliverySetting
		if c.Bool("register") {
			register = smpp.FinalDeliveryReceipt
		}
		var codec pdutext.Codec
		switch c.String("encoding") {
		case "ucs2", "ucs-2":
			codec = pdutext.UCS2(text)
		case "latin1", "latin-1":
			codec = pdutext.Latin1(text)
		default:
			codec = pdutext.Raw(text)
		}
		sm, err := tx.Submit(&smpp.ShortMessage{
			Src:                  sender,
			Dst:                  recipient,
			Text:                 codec,
			Register:             register,
			ServiceType:          c.String("service-type"),
			SourceAddrTON:        uint8(c.Int("source-addr-ton")),
			SourceAddrNPI:        uint8(c.Int("source-addr-npi")),
			DestAddrTON:          uint8(c.Int("dest-addr-ton")),
			DestAddrNPI:          uint8(c.Int("dest-addr-npi")),
			ESMClass:             uint8(c.Int("esm-class")),
			ProtocolID:           uint8(c.Int("protocol-id")),
			PriorityFlag:         uint8(c.Int("priority-flag")),
			ScheduleDeliveryTime: c.String("schedule-delivery-time"),
Пример #9
0
func TestSubmitMulti(t *testing.T) {
	//construct a byte array with the UnsuccessSme
	var bArray []byte
	bArray = append(bArray, byte(0x00))       // TON
	bArray = append(bArray, byte(0x00))       // NPI
	bArray = append(bArray, []byte("123")...) // Address
	bArray = append(bArray, byte(0x00))       // Error
	bArray = append(bArray, byte(0x00))       // Error
	bArray = append(bArray, byte(0x00))       // Error
	bArray = append(bArray, byte(0x11))       // Error
	bArray = append(bArray, byte(0x00))       // null terminator

	s := smpptest.NewUnstartedServer()
	s.Handler = func(c smpptest.Conn, p pdu.Body) {
		switch p.Header().ID {
		case pdu.SubmitMultiID:
			r := pdu.NewSubmitMultiResp()
			r.Header().Seq = p.Header().Seq
			r.Fields().Set(pdufield.MessageID, "foobar")
			r.Fields().Set(pdufield.NoUnsuccess, uint8(1))
			r.Fields().Set(pdufield.UnsuccessSme, bArray)
			c.Write(r)
		default:
			smpptest.EchoHandler(c, p)
		}
	}
	s.Start()
	defer s.Close()
	tx := &Transmitter{
		Addr:   s.Addr(),
		User:   smpptest.DefaultUser,
		Passwd: smpptest.DefaultPasswd,
	}
	defer tx.Close()
	conn := <-tx.Bind()
	switch conn.Status() {
	case Connected:
	default:
		t.Fatal(conn.Error())
	}
	sm, err := tx.Submit(&ShortMessage{
		Src:      "root",
		DstList:  []string{"123", "2233", "32322", "4234234"},
		DLs:      []string{"DistributionList1"},
		Text:     pdutext.Raw("Lorem ipsum"),
		Validity: 10 * time.Minute,
		Register: NoDeliveryReceipt,
	})
	if err != nil {
		t.Fatal(err)
	}
	msgid := sm.RespID()
	if msgid == "" {
		t.Fatalf("pdu does not contain msgid: %#v", sm.Resp())
	}
	if msgid != "foobar" {
		t.Fatalf("unexpected msgid: want foobar, have %q", msgid)
	}
	noUncess, _ := sm.NumbUnsuccess()
	if noUncess != 1 {
		t.Fatalf("unexpected number of unsuccess %d", noUncess)
	}
	uncessSmes, _ := sm.UnsuccessSmes()
	if len(uncessSmes) != 1 {
		t.Fatalf("unsucess sme list should have a size of 1, has %d", len(uncessSmes))
	}
}
Пример #10
0
func TestTransceiver(t *testing.T) {
	s := smpptest.NewUnstartedServer()
	s.Handler = func(c smpptest.Conn, p pdu.Body) {
		switch p.Header().ID {
		case pdu.SubmitSMID:
			r := pdu.NewSubmitSMResp()
			r.Header().Seq = p.Header().Seq
			r.Fields().Set(pdufield.MessageID, "foobar")
			c.Write(r)
			pf := p.Fields()
			rd := pf[pdufield.RegisteredDelivery]
			if rd.Bytes()[0] == 0 {
				return
			}
			r = pdu.NewDeliverSM()
			f := r.Fields()
			f.Set(pdufield.SourceAddr, pf[pdufield.SourceAddr])
			f.Set(pdufield.DestinationAddr, pf[pdufield.DestinationAddr])
			f.Set(pdufield.ShortMessage, pf[pdufield.ShortMessage])
			c.Write(r)
		default:
			smpptest.EchoHandler(c, p)
		}
	}
	s.Start()
	defer s.Close()
	ack := make(chan error)
	receiver := func(p pdu.Body) {
		defer close(ack)
		if p.Header().ID != pdu.DeliverSMID {
			ack <- fmt.Errorf("unexpected PDU: %s", p.Header().ID)
		}
	}
	tc := &Transceiver{
		Addr:    s.Addr(),
		User:    smpptest.DefaultUser,
		Passwd:  smpptest.DefaultPasswd,
		Handler: receiver,
	}
	defer tc.Close()
	conn := <-tc.Bind()
	switch conn.Status() {
	case Connected:
	default:
		t.Fatal(conn.Error())
	}
	sm, err := tc.Submit(&ShortMessage{
		Src:      "root",
		Dst:      "foobar",
		Text:     pdutext.Raw("Lorem ipsum"),
		Register: FinalDeliveryReceipt,
	})
	if err != nil {
		t.Fatal(err)
	}
	msgid := sm.RespID()
	if msgid == "" {
		t.Fatalf("pdu does not contain msgid: %#v", sm.Resp())
	}
	if msgid != "foobar" {
		t.Fatalf("unexpected msgid: want foobar, have %q", msgid)
	}
	select {
	case err := <-ack:
		if err != nil {
			t.Fatal(err)
		}
	case <-time.After(time.Second):
		t.Fatal("timeout waiting for ack")
	}
}