// auth authenticate new clients. func (srv *Server) auth(c *conn) error { p, err := c.Read() if err != nil { return err } var resp pdu.Body switch p.Header().ID { case pdu.BindTransmitterID: resp = pdu.NewBindTransmitterResp() case pdu.BindReceiverID: resp = pdu.NewBindReceiverResp() case pdu.BindTransceiverID: resp = pdu.NewBindTransceiverResp() default: return errors.New("unexpected pdu, want bind") } f := p.Fields() user := f[pdufield.SystemID] passwd := f[pdufield.Password] if user == nil || passwd == nil { return errors.New("malformed pdu, missing system_id/password") } if user.String() != srv.User { return errors.New("invalid user") } if passwd.String() != srv.Passwd { return errors.New("invalid passwd") } resp.Fields().Set(pdufield.SystemID, DefaultSystemID) if err = c.Write(resp); err != nil { return err } return nil }
func (t *Transmitter) do(p pdu.Body) (*tx, error) { t.conn.Lock() notbound := t.conn.client == nil t.conn.Unlock() if notbound { return nil, ErrNotBound } rc := make(chan *tx, 1) seq := p.Header().Seq t.tx.Lock() t.tx.inflight[seq] = rc t.tx.Unlock() defer func() { close(rc) t.tx.Lock() delete(t.tx.inflight, seq) t.tx.Unlock() }() err := t.conn.Write(p) if err != nil { return nil, err } select { case resp := <-rc: return resp, nil case <-time.After(time.Second): return nil, errors.New("timeout waiting for response") } }
// Write implements the Conn interface. func (c *conn) Write(p pdu.Body) error { var b bytes.Buffer err := p.SerializeTo(&b) if err != nil { return err } _, err = io.Copy(c.w, &b) if err != nil { return err } return c.w.Flush() }
// Handler handles DeliverSM coming from a Transceiver SMPP connection. // It broadcasts received delivery receipt to all registered peers. func (pool *deliveryPool) Handler(p pdu.Body) { switch p.Header().ID { case pdu.DeliverSMID: f := p.Fields() dr := &DeliveryReceipt{ Src: f[pdufield.SourceAddr].String(), Dst: f[pdufield.DestinationAddr].String(), Text: f[pdufield.ShortMessage].String(), } pool.Broadcast(dr) } }
// bind attempts to bind the connection. func bind(c Conn, p pdu.Body) (pdu.Body, error) { f := p.Fields() f.Set(pdufield.InterfaceVersion, 0x34) err := c.Write(p) if err != nil { return nil, err } resp, err := c.Read() if err != nil { return nil, err } h := resp.Header() if h.Status != 0 { return nil, h.Status } return resp, nil }
func (t *Transmitter) do(p pdu.Body) (*tx, error) { t.conn.Lock() notbound := t.conn.client == nil t.conn.Unlock() if notbound { return nil, ErrNotBound } if t.conn.WindowSize > 0 { inflight := uint(atomic.AddInt32(&t.tx.count, 1)) defer func(t *Transmitter) { atomic.AddInt32(&t.tx.count, -1) }(t) if inflight > t.conn.WindowSize { return nil, ErrMaxWindowSize } } rc := make(chan *tx, 1) seq := p.Header().Seq t.tx.Lock() t.tx.inflight[seq] = rc t.tx.Unlock() defer func() { close(rc) t.tx.Lock() delete(t.tx.inflight, seq) t.tx.Unlock() }() err := t.conn.Write(p) if err != nil { return nil, err } select { case resp := <-rc: if resp.Err != nil { return nil, resp.Err } return resp, nil case <-t.conn.respTimeout(): return nil, errors.New("timeout waiting for response") } }
func (t *Transmitter) submitMsg(sm *ShortMessage, p pdu.Body, dataCoding uint8) (*ShortMessage, error) { 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)) // Check if the message has validity set. 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, sm.ESMClass) 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, dataCoding) 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 }
func pduHandler(c smpptest.Conn, p pdu.Body) { src := p.Fields()[pdufield.SourceAddr] fail := src != nil && src.String() == "root" switch p.Header().ID { case pdu.SubmitSMID: r := pdu.NewSubmitSMResp() r.Header().Seq = p.Header().Seq if fail { r.Header().Status = 0x00000045 // submitsm failed } else { r.Fields().Set(pdufield.MessageID, "foobar") } c.Write(r) rd := p.Fields()[pdufield.RegisteredDelivery] if rd == nil || rd.Bytes()[0] == 0 { return } r = pdu.NewDeliverSM() rf := r.Fields() pf := p.Fields() rf.Set(pdufield.SourceAddr, pf[pdufield.SourceAddr]) rf.Set(pdufield.DestinationAddr, pf[pdufield.DestinationAddr]) rf.Set(pdufield.ShortMessage, "delivery receipt here") c.Write(r) case pdu.QuerySMID: r := pdu.NewQuerySMResp() r.Header().Seq = p.Header().Seq if fail { r.Header().Status = 0x00000067 // querysm failed } else { pf := p.Fields() rf := r.Fields() rf.Set(pdufield.MessageID, pf[pdufield.MessageID]) rf.Set(pdufield.MessageState, 2) // DELIVERED } c.Write(r) default: smpptest.EchoHandler(c, p) } }
func (t *Transmitter) submitMsgMulti(sm *ShortMessage, p pdu.Body, dataCoding uint8) (*ShortMessage, error) { numberOfDest := len(sm.DstList) + len(sm.DLs) // TODO: Validate numbers and lists according to size if numberOfDest > MaxDestinationAddress { return nil, fmt.Errorf("Error: Max number of destination addresses allowed is %d, trying to send to %d", MaxDestinationAddress, numberOfDest) } // Put destination addresses and lists inside an byte array var bArray []byte // destination addresses for _, destAddr := range sm.DstList { // 1 - SME Address bArray = append(bArray, byte(0x01)) bArray = append(bArray, byte(sm.DestAddrTON)) bArray = append(bArray, byte(sm.DestAddrNPI)) bArray = append(bArray, []byte(destAddr)...) // null terminator bArray = append(bArray, byte(0x00)) } // distribution lists for _, destList := range sm.DLs { // 2 - Distribution List bArray = append(bArray, byte(0x02)) bArray = append(bArray, []byte(destList)...) // null terminator bArray = append(bArray, byte(0x00)) } f := p.Fields() f.Set(pdufield.SourceAddr, sm.Src) f.Set(pdufield.DestinationList, bArray) f.Set(pdufield.ShortMessage, sm.Text) f.Set(pdufield.NumberDests, uint8(numberOfDest)) f.Set(pdufield.RegisteredDelivery, uint8(sm.Register)) // Check if the message has validity set. 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.ESMClass, sm.ESMClass) 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, dataCoding) 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.SubmitMultiRespID { return sm, fmt.Errorf("unexpected PDU ID: %s", id) } if s := resp.PDU.Header().Status; s != 0 { return sm, s } return sm, resp.Err }