func TestDmtAgentDryRun1(t *testing.T) { if !*testIntegration { return } ccr := diam.NewRequest(diam.CreditControl, 4, nil) ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("cgrates;1451911932;00082")) ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA")) ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org")) ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)) ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("pubsub1")) // Match specific DryRun profile ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(4)) ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(0)) ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2016, 1, 5, 11, 30, 10, 0, time.UTC))) if _, err := ccr.NewAVP("Framed-IP-Address", avp.Mbit, 0, datatype.UTF8String("10.228.16.4")); err != nil { t.Error(err) } if err := dmtClient.SendMessage(ccr); err != nil { t.Error(err) } time.Sleep(time.Duration(100) * time.Millisecond) msg := dmtClient.ReceivedMessage() if msg == nil { t.Fatal("No message returned") } if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil { t.Error(err) } else if len(avps) == 0 { t.Error("Result-Code") } else if strResult := avpValAsString(avps[0]); strResult != "300" { // Result-Code set in the template t.Errorf("Expecting 300, received: %s", strResult) } }
func NewDiameterClient(addr, originHost, originRealm string, vendorId int, productName string, firmwareRev int) (*DiameterClient, error) { cfg := &sm.Settings{ OriginHost: datatype.DiameterIdentity(originHost), OriginRealm: datatype.DiameterIdentity(originRealm), VendorID: datatype.Unsigned32(vendorId), ProductName: datatype.UTF8String(productName), FirmwareRevision: datatype.Unsigned32(firmwareRev), } handlers := sm.New(cfg) cli := &sm.Client{ Handler: handlers, MaxRetransmits: 3, RetransmitInterval: time.Second, EnableWatchdog: true, WatchdogInterval: 5 * time.Second, AcctApplicationID: []*diam.AVP{ // Advertise that we want support for both // Accounting applications 4 and 999. diam.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)), // RFC 4006 }, } conn, err := cli.Dial(addr) if err != nil { return nil, err } return &DiameterClient{conn: conn, handlers: handlers}, nil }
// Converts itself into DiameterMessage func (self *CCA) AsDiameterMessage() (*diam.Message, error) { if _, err := self.diamMessage.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String(self.SessionId)); err != nil { return nil, err } if _, err := self.diamMessage.NewAVP("Origin-Host", avp.Mbit, 0, datatype.DiameterIdentity(self.OriginHost)); err != nil { return nil, err } if _, err := self.diamMessage.NewAVP("Origin-Realm", avp.Mbit, 0, datatype.DiameterIdentity(self.OriginRealm)); err != nil { return nil, err } if _, err := self.diamMessage.NewAVP("Auth-Application-Id", avp.Mbit, 0, datatype.Unsigned32(self.AuthApplicationId)); err != nil { return nil, err } if _, err := self.diamMessage.NewAVP("CC-Request-Type", avp.Mbit, 0, datatype.Enumerated(self.CCRequestType)); err != nil { return nil, err } if _, err := self.diamMessage.NewAVP("CC-Request-Number", avp.Mbit, 0, datatype.Enumerated(self.CCRequestNumber)); err != nil { return nil, err } if _, err := self.diamMessage.NewAVP(avp.ResultCode, avp.Mbit, 0, datatype.Unsigned32(self.ResultCode)); err != nil { return nil, err } ccTimeAvp, err := self.diamMessage.Dictionary().FindAVP(self.diamMessage.Header.ApplicationID, "CC-Time") if err != nil { return nil, err } if _, err := self.diamMessage.NewAVP("Granted-Service-Unit", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(ccTimeAvp.Code, avp.Mbit, 0, datatype.Unsigned32(self.GrantedServiceUnit.CCTime))}}); err != nil { return nil, err } return self.diamMessage, nil }
// Used when sending from client to agent func (self *CCR) AsDiameterMessage() (*diam.Message, error) { m := self.AsBareDiameterMessage() if _, err := m.NewAVP("Destination-Host", avp.Mbit, 0, datatype.DiameterIdentity(self.DestinationHost)); err != nil { return nil, err } if _, err := m.NewAVP("Destination-Realm", avp.Mbit, 0, datatype.DiameterIdentity(self.DestinationRealm)); err != nil { return nil, err } if _, err := m.NewAVP("Service-Context-Id", avp.Mbit, 0, datatype.UTF8String(self.ServiceContextId)); err != nil { return nil, err } if _, err := m.NewAVP("Event-Timestamp", avp.Mbit, 0, datatype.Time(self.EventTimestamp)); err != nil { return nil, err } for _, subscriptionId := range self.SubscriptionId { if _, err := m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(subscriptionId.SubscriptionIdType)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String(subscriptionId.SubscriptionIdData)), // Subscription-Id-Data }}); err != nil { return nil, err } } if _, err := m.NewAVP("Service-Identifier", avp.Mbit, 0, datatype.Unsigned32(self.ServiceIdentifier)); err != nil { return nil, err } if _, err := m.NewAVP("Requested-Service-Unit", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(self.RequestedServiceUnit.CCTime))}}); err != nil { // CC-Time return nil, err } if _, err := m.NewAVP("Used-Service-Unit", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(self.UsedServiceUnit.CCTime))}}); err != nil { // CC-Time return nil, err } if _, err := m.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information AVP: []*diam.AVP{ diam.NewAVP(831, avp.Mbit, 10415, datatype.UTF8String(self.ServiceInformation.INInformation.CallingPartyAddress)), // Calling-Party-Address diam.NewAVP(832, avp.Mbit, 10415, datatype.UTF8String(self.ServiceInformation.INInformation.CalledPartyAddress)), // Called-Party-Address diam.NewAVP(20327, avp.Mbit, 2011, datatype.UTF8String(self.ServiceInformation.INInformation.RealCalledNumber)), // Real-Called-Number diam.NewAVP(20339, avp.Mbit, 2011, datatype.Unsigned32(self.ServiceInformation.INInformation.ChargeFlowType)), // Charge-Flow-Type diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String(self.ServiceInformation.INInformation.CallingVlrNumber)), // Calling-Vlr-Number diam.NewAVP(20303, avp.Mbit, 2011, datatype.UTF8String(self.ServiceInformation.INInformation.CallingCellIDOrSAI)), // Calling-CellID-Or-SAI diam.NewAVP(20313, avp.Mbit, 2011, datatype.UTF8String(self.ServiceInformation.INInformation.BearerCapability)), // Bearer-Capability diam.NewAVP(20321, avp.Mbit, 2011, datatype.UTF8String(self.ServiceInformation.INInformation.CallReferenceNumber)), // Call-Reference-Number diam.NewAVP(20322, avp.Mbit, 2011, datatype.UTF8String(self.ServiceInformation.INInformation.MSCAddress)), // MSC-Address diam.NewAVP(20324, avp.Mbit, 2011, datatype.Unsigned32(self.ServiceInformation.INInformation.TimeZone)), // Time-Zone diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String(self.ServiceInformation.INInformation.CalledPartyNP)), // Called-Party-NP diam.NewAVP(20386, avp.Mbit, 2011, datatype.UTF8String(self.ServiceInformation.INInformation.SSPTime)), // SSP-Time }, }), }}); err != nil { return nil, err } return m, nil }
func TestDWR_MissingOriginStateID(t *testing.T) { m := diam.NewRequest(diam.CapabilitiesExchange, 0, dict.Default) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) dwr := new(DWR) err := dwr.Parse(m) if err != nil && err != ErrMissingOriginStateID { t.Fatal("Unexpected error:", err) } }
// AsBareDiameterMessage converts CCR into a bare DiameterMessage // Compatible with the required fields of CCA func (self *CCR) AsBareDiameterMessage() *diam.Message { m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(self.SessionId)) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity(self.OriginHost)) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity(self.OriginRealm)) m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(self.AuthApplicationId)) m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(self.CCRequestType)) m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(self.CCRequestNumber)) return m }
func TestDWR_OK(t *testing.T) { m := diam.NewRequest(diam.CapabilitiesExchange, 0, dict.Default) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) m.NewAVP(avp.OriginStateID, avp.Mbit, 0, datatype.Unsigned32(1)) dwr := new(DWR) err := dwr.Parse(m) if err != nil { t.Fatal(err) } }
// AsBareDiameterMessage converts CCA into a bare DiameterMessage func (self *CCA) AsBareDiameterMessage() *diam.Message { var m diam.Message utils.Clone(self.diamMessage, &m) m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(self.SessionId)) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity(self.OriginHost)) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity(self.OriginRealm)) m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(self.AuthApplicationId)) m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(self.CCRequestType)) m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Enumerated(self.CCRequestNumber)) m.NewAVP(avp.ResultCode, avp.Mbit, 0, datatype.Unsigned32(self.ResultCode)) return &m }
func TestCER_MissingOriginStateID(t *testing.T) { m := diam.NewRequest(diam.CapabilitiesExchange, 0, dict.Default) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) cer := new(CER) _, err := cer.Parse(m) if err == nil { t.Fatal("Broken CER was parsed with no errors") } if err != ErrMissingOriginStateID { t.Fatal("Unexpected error:", err) } }
func storedCdrToCCR(cdr *engine.StoredCdr, originHost, originRealm string, vendorId int, productName string, firmwareRev int, debitInterval time.Duration, callEnded bool) *diam.Message { sid := "session;" + strconv.Itoa(int(rand.Uint32())) reqType, reqNr, ccTime := disectUsageForCCR(cdr.Usage, debitInterval, callEnded) m := diam.NewRequest(272, 4, nil) m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(sid)) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity(originHost)) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity(originRealm)) m.NewAVP(avp.DestinationHost, avp.Mbit, 0, datatype.DiameterIdentity(originHost)) m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, datatype.DiameterIdentity(originRealm)) m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)) m.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("*****@*****.**")) m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(reqType)) m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Enumerated(reqNr)) m.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(cdr.AnswerTime)) m.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(0)), diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String(cdr.Account)), }}) m.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(1)), diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("20921006232651")), }}) m.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0)) m.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(ccTime))}}) /* m.NewAVP(avp.ServiceInformation, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(20300, avp.Mbit, 0, &diam.GroupedAVP{ // IN-Information AVP: []*diam.AVP{ diam.NewAVP(avp.CallingPartyAddress, avp.Mbit, 0, datatype.UTF8String(cdr.Account)), diam.NewAVP(avp.CalledPartyAddress, avp.Mbit, 0, datatype.UTF8String(cdr.Destination)), diam.NewAVP(20327, avp.Mbit, 0, datatype.UTF8String(cdr.Destination)), // Real-Called-Number diam.NewAVP(20339, avp.Mbit, 0, datatype.Unsigned32(0)), // Charge-Flow-Type diam.NewAVP(20302, avp.Mbit, 0, datatype.UTF8String("33657954968")), // Calling-Vlr-Number diam.NewAVP(20303, avp.Mbit, 0, datatype.UTF8String("31901485301525")), // Calling-CellID-Or-SAI diam.NewAVP(avp.BearerCapability, avp.Mbit, 0, datatype.UTF8String("31901485301525")), diam.NewAVP(20321, avp.Mbit, 0, datatype.UTF8String("31901485301525")), // Call-Reference-Number diam.NewAVP(avp.MSCAddress, avp.Mbit, 0, datatype.UTF8String("")), diam.NewAVP(20324, avp.Mbit, 0, datatype.UTF8String("0")), // Time-Zone diam.NewAVP(20385, avp.Mbit, 0, datatype.UTF8String("")), // Called-Party-NP diam.NewAVP(20386, avp.Mbit, 0, datatype.UTF8String("20091020120101")), // SSP-Time }, }), }}) */ return m }
func TestCEA_MissingOriginStateID(t *testing.T) { m := diam.NewMessage(diam.CapabilitiesExchange, 0, 0, 0, 0, nil) m.NewAVP(avp.ResultCode, avp.Mbit, 0, datatype.Unsigned32(diam.Success)) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) cea := new(CEA) err := cea.Parse(m) if err == nil { t.Fatal("Broken CEA was parsed with no errors") } if err != nil && err != ErrMissingOriginStateID { t.Fatal("Unexpected error:", err) } }
func TestAvpValAsString(t *testing.T) { originHostStr := "unit_test" a := diam.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity(originHostStr)) if avpValStr := avpValAsString(a); avpValStr != originHostStr { t.Errorf("Expected: %s, received: %s", originHostStr, avpValStr) } }
func TestDecodeMessageWithGroupedAVP(t *testing.T) { m := NewRequest(257, 0, dict.Default) m.NewAVP(264, 0x40, 0, datatype.DiameterIdentity("client")) a, _ := DecodeAVP(testGroupedAVP, 0, dict.Default) m.AddAVP(a) t.Logf("Message:\n%s", m) }
func TestCER_AcctAppID(t *testing.T) { m := diam.NewRequest(diam.CapabilitiesExchange, 0, dict.Default) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) m.NewAVP(avp.OriginStateID, avp.Mbit, 0, datatype.Unsigned32(1)) m.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(1001)) cer := new(CER) _, err := cer.Parse(m) if err != nil { t.Fatal(err) } if app := cer.Applications(); len(app) != 1 { if app[0] != 1001 { t.Fatalf("Unexpected app ID. Want 1001, have %d", app[0]) } } }
// Creates the message handlers func (self *DiameterAgent) handlers() diam.Handler { settings := &sm.Settings{ OriginHost: datatype.DiameterIdentity(self.cgrCfg.DiameterAgentCfg().OriginHost), OriginRealm: datatype.DiameterIdentity(self.cgrCfg.DiameterAgentCfg().OriginRealm), VendorID: datatype.Unsigned32(self.cgrCfg.DiameterAgentCfg().VendorId), ProductName: datatype.UTF8String(self.cgrCfg.DiameterAgentCfg().ProductName), FirmwareRevision: datatype.Unsigned32(utils.DIAMETER_FIRMWARE_REVISION), } dSM := sm.New(settings) dSM.HandleFunc("CCR", self.handleCCR) dSM.HandleFunc("ALL", self.handleALL) go func() { for err := range dSM.ErrorReports() { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> StateMachine error: %+v", err)) } }() return dSM }
func main() { addr := flag.String("addr", ":3868", "address in the form of ip:port to listen on") ppaddr := flag.String("pprof_addr", ":9000", "address in form of ip:port for the pprof server") host := flag.String("diam_host", "server", "diameter identity host") realm := flag.String("diam_realm", "go-diameter", "diameter identity realm") certFile := flag.String("cert_file", "", "tls certificate file (optional)") keyFile := flag.String("key_file", "", "tls key file (optional)") silent := flag.Bool("s", false, "silent mode, useful for benchmarks") flag.Parse() // Load our custom dictionary on top of the default one, which // always have the Base Protocol (RFC6733) and Credit Control // Application (RFC4006). err := dict.Default.Load(bytes.NewReader([]byte(helloDictionary))) if err != nil { log.Fatal(err) } settings := &sm.Settings{ OriginHost: datatype.DiameterIdentity(*host), OriginRealm: datatype.DiameterIdentity(*realm), VendorID: 13, ProductName: "go-diameter", FirmwareRevision: 1, } // Create the state machine (mux) and set its message handlers. mux := sm.New(settings) mux.Handle("HMR", handleHMR(*silent)) mux.Handle("ACR", handleACR(*silent)) mux.HandleFunc("ALL", handleALL) // Catch all. // Print error reports. go printErrors(mux.ErrorReports()) if len(*ppaddr) > 0 { go func() { log.Fatal(http.ListenAndServe(*ppaddr, nil)) }() } err = listen(*addr, *certFile, *keyFile, mux) if err != nil { log.Fatal(err) } }
func TestCER_AuthNotAcctAppID(t *testing.T) { m := diam.NewRequest(diam.CapabilitiesExchange, 0, dict.Default) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) m.NewAVP(avp.OriginStateID, avp.Mbit, 0, datatype.Unsigned32(1)) m.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(1002)) cer := new(CER) _, err := cer.Parse(m) if err == nil { t.Fatal("Broken CER was parsed with no errors") } appErr, ok := err.(*ErrNoCommonApplication) if !ok { t.Fatal(err) } if appErr.ID != 1002 { t.Fatalf("Unexpected app ID. Want 1002, have %d", appErr.ID) } }
func TestCEA_FailedAcctAppID(t *testing.T) { m := diam.NewMessage(diam.CapabilitiesExchange, 0, 0, 0, 0, nil) m.NewAVP(avp.ResultCode, avp.Mbit, 0, datatype.Unsigned32(diam.Success)) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) m.NewAVP(avp.OriginStateID, avp.Mbit, 0, datatype.Unsigned32(1)) m.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(1000)) cea := new(CEA) err := cea.Parse(m) if err == nil { t.Fatal("Broken CER was parsed with no errors") } appErr, ok := err.(*ErrNoCommonApplication) if !ok { t.Fatal(err) } if appErr.ID != 1000 { t.Fatalf("Unexpected app ID. Want 1000, have %d", appErr.ID) } }
func TestCEA_NoCommonApplication(t *testing.T) { m := diam.NewMessage(diam.CapabilitiesExchange, 0, 0, 0, 0, dict.Default) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) m.NewAVP(avp.OriginStateID, avp.Mbit, 0, datatype.Unsigned32(1)) m.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(2)) cer := new(CER) _, err := cer.Parse(m) if err == nil { t.Fatal("Broken CER was parsed with no errors") } appErr, ok := err.(*ErrNoCommonApplication) if !ok { t.Fatal("Unexpected error:", err.Error()) } if appErr.ID != 2 { t.Fatalf("Unexpected app ID. Want 2, have %d", appErr.ID) } if !strings.Contains(appErr.Error(), "acct application 2") { t.Fatalf("Unexpected error message: %s", appErr) } }
func TestFromCEA(t *testing.T) { cer := &smparser.CEA{ OriginHost: datatype.DiameterIdentity("foobar"), OriginRealm: datatype.DiameterIdentity("test"), } meta := FromCEA(cer) if meta.OriginHost != cer.OriginHost { t.Fatalf("Unexpected OriginHost. Want %q, have %q", cer.OriginHost, meta.OriginHost) } if meta.OriginRealm != cer.OriginRealm { t.Fatalf("Unexpected OriginRealm. Want %q, have %q", cer.OriginRealm, meta.OriginRealm) } ctx := NewContext(context.Background(), meta) data, ok := FromContext(ctx) if !ok { t.Fatal("Metadata not present in this context") } if data != meta { t.Fatalf("Unexpected Metadata. Want %#v, have %#v", meta, data) } }
func NewDiameterClient(addr, originHost, originRealm string, vendorId int, productName string, firmwareRev int, dictsDir string) (*DiameterClient, error) { cfg := &sm.Settings{ OriginHost: datatype.DiameterIdentity(originHost), OriginRealm: datatype.DiameterIdentity(originRealm), VendorID: datatype.Unsigned32(vendorId), ProductName: datatype.UTF8String(productName), FirmwareRevision: datatype.Unsigned32(firmwareRev), } dSM := sm.New(cfg) go func() { for err := range dSM.ErrorReports() { utils.Logger.Err(fmt.Sprintf("<DiameterClient> StateMachine error: %+v", err)) } }() cli := &sm.Client{ Handler: dSM, MaxRetransmits: 3, RetransmitInterval: time.Second, EnableWatchdog: true, WatchdogInterval: 5 * time.Second, AcctApplicationID: []*diam.AVP{ diam.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)), // RFC 4006 }, } if len(dictsDir) != 0 { if err := loadDictionaries(dictsDir, "DiameterClient"); err != nil { return nil, err } } conn, err := cli.Dial(addr) if err != nil { return nil, err } dc := &DiameterClient{conn: conn, handlers: dSM} dSM.HandleFunc("ALL", dc.handleALL) return dc, nil }
func TestNewAVP(t *testing.T) { a := NewAVP( avp.OriginHost, // Code avp.Mbit, // Flags 0, // Vendor datatype.DiameterIdentity("foobar"), // Data ) if a.Length != 14 { // Length in the AVP header t.Fatalf("Unexpected length. Want 14, have %d", a.Length) } if a.Len() != 16 { // With padding t.Fatalf("Unexpected length (with padding). Want 16, have %d\n", a.Len()) } t.Log(a) }
func TestNewMessage(t *testing.T) { want, _ := ReadMessage(bytes.NewReader(testMessage), dict.Default) m := NewMessage(CapabilitiesExchange, RequestFlag, 0, 0xa8cc407d, 0xa8c1b2b4, dict.Default) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("test")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("localhost")) m.NewAVP(avp.HostIPAddress, avp.Mbit, 0, datatype.Address(net.ParseIP("10.1.0.1"))) m.NewAVP(avp.VendorID, avp.Mbit, 0, datatype.Unsigned32(13)) m.NewAVP(avp.ProductName, 0, 0, datatype.UTF8String("go-diameter")) m.NewAVP(avp.OriginStateID, avp.Mbit, 0, datatype.Unsigned32(1397760650)) m.NewAVP(avp.SupportedVendorID, avp.Mbit, 0, datatype.Unsigned32(10415)) m.NewAVP(avp.SupportedVendorID, avp.Mbit, 0, datatype.Unsigned32(13)) m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)) m.NewAVP(avp.InbandSecurityID, avp.Mbit, 0, datatype.Unsigned32(0)) m.NewAVP(avp.VendorSpecificApplicationID, avp.Mbit, 0, &GroupedAVP{ AVP: []*AVP{ NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)), NewAVP(avp.VendorID, avp.Mbit, 0, datatype.Unsigned32(10415)), }, }) m.NewAVP(avp.FirmwareRevision, 0, 0, datatype.Unsigned32(1)) if m.Len() != want.Len() { t.Fatalf("Unexpected message length.\nWant: %d\n%s\nHave: %d\n%s", want.Len(), want, m.Len(), m) } a, err := m.Serialize() if err != nil { t.Fatal(err) } b, _ := want.Serialize() if !bytes.Equal(a, b) { t.Fatalf("Unexpected message.\nWant:\n%s\n%s\nHave:\n%s\n%s", want, hex.Dump(b), m, hex.Dump(a)) } t.Logf("%d bytes\n%s", len(a), m) t.Logf("Message:\n%s", hex.Dump(a)) }
func TestCEA(t *testing.T) { m := diam.NewMessage(diam.CapabilitiesExchange, 0, 0, 0, 0, nil) m.NewAVP(avp.ResultCode, avp.Mbit, 0, datatype.Unsigned32(diam.Success)) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("foobar")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("test")) m.NewAVP(avp.OriginStateID, avp.Mbit, 0, datatype.Unsigned32(1)) m.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)) cea := new(CEA) if err := cea.Parse(m); err != nil { t.Fatal(err) } if cea.ResultCode != diam.Success { t.Fatalf("Unexpected Result-Code. Want %d, have %d", diam.Success, cea.ResultCode) } if cea.OriginStateID != 1 { t.Fatalf("Unexpected Result-Code. Want 1, have %d", cea.OriginStateID) } if app := cea.Applications(); len(app) != 1 { if app[0] != 4 { t.Fatalf("Unexpected app ID. Want 4, have %d", app[0]) } } }
func TestEncodeAVP(t *testing.T) { a := &AVP{ Code: avp.OriginHost, Flags: avp.Mbit, Data: datatype.DiameterIdentity("client"), } b, err := a.Serialize() if err != nil { t.Fatal(err) } if !bytes.Equal(b, testAVP[0]) { t.Fatalf("AVPs do not match.\nWant:\n%s\nHave:\n%s", hex.Dump(testAVP[0]), hex.Dump(b)) } t.Log(hex.Dump(b)) }
func main() { addr := flag.String("addr", "localhost:3868", "address in form of ip:port to connect to") ssl := flag.Bool("ssl", false, "connect to server using tls") host := flag.String("diam_host", "client", "diameter identity host") realm := flag.String("diam_realm", "go-diameter", "diameter identity realm") certFile := flag.String("cert_file", "", "tls client certificate file (optional)") keyFile := flag.String("key_file", "", "tls client key file (optional)") hello := flag.Bool("hello", false, "send a hello message, wait for the response and disconnect") bench := flag.Bool("bench", false, "benchmark the server by sending ACR messages") benchCli := flag.Int("bench_clients", 1, "number of client connections") benchMsgs := flag.Int("bench_msgs", 1000, "number of ACR messages to send") flag.Parse() if len(*addr) == 0 { flag.Usage() } // Load our custom dictionary on top of the default one. err := dict.Default.Load(bytes.NewReader([]byte(helloDictionary))) if err != nil { log.Fatal(err) } cfg := &sm.Settings{ OriginHost: datatype.DiameterIdentity(*host), OriginRealm: datatype.DiameterIdentity(*realm), VendorID: 13, ProductName: "go-diameter", OriginStateID: datatype.Unsigned32(time.Now().Unix()), FirmwareRevision: 1, } // Create the state machine (it's a diam.ServeMux) and client. mux := sm.New(cfg) cli := &sm.Client{ Dict: dict.Default, Handler: mux, MaxRetransmits: 3, RetransmitInterval: time.Second, EnableWatchdog: true, WatchdogInterval: 5 * time.Second, AcctApplicationID: []*diam.AVP{ // Advertise that we want support for both // Accounting applications 4 and 999. diam.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)), // RFC 4006 diam.NewAVP(avp.AcctApplicationID, avp.Mbit, 0, datatype.Unsigned32(helloApplication)), }, } // Set message handlers. done := make(chan struct{}, 1000) mux.Handle("HMA", handleHMA(done)) mux.Handle("ACA", handleACA(done)) // Print error reports. go printErrors(mux.ErrorReports()) connect := func() (diam.Conn, error) { return dial(cli, *addr, *certFile, *keyFile, *ssl) } if *bench { cli.EnableWatchdog = false benchmark(connect, cfg, *benchCli, *benchMsgs, done) return } if *hello { c, err := connect() if err != nil { log.Fatal(err) } err = sendHMR(c, cfg) if err != nil { log.Fatal(err) } select { case <-done: case <-time.After(5 * time.Second): log.Fatal("timeout: no hello answer received") } return } // Makes a persisent connection with back-off. log.Println("Use wireshark to see the messages, or try -hello") backoff := 1 for { c, err := connect() if err != nil { log.Println(err) backoff *= 2 if backoff > 20 { backoff = 20 } time.Sleep(time.Duration(backoff) * time.Second) continue } log.Println("Client connected, handshake ok") backoff = 1 <-c.(diam.CloseNotifier).CloseNotify() log.Println("Client disconnected") } }
func TestDmtAgentSendDataGrpTerminate(t *testing.T) { ccr := diam.NewRequest(diam.CreditControl, 4, nil) ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("testdatagrp")) ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA")) ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org")) ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)) ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("*****@*****.**")) ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(3)) ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(1)) ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2016, 1, 5, 11, 30, 10, 0, time.UTC))) ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(0)), diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data }}) ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(1)), diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("104502200011")), // Subscription-Id-Data }}) ccr.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0)) ccr.NewAVP(avp.RequestedAction, avp.Mbit, 0, datatype.Enumerated(0)) ccr.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(1))}}) ccr.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{ // AVP: []*diam.AVP{ diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information AVP: []*diam.AVP{ diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("22509")), // Calling-Vlr-Number diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("4002")), // Called-Party-NP }, }), diam.NewAVP(2000, avp.Mbit, 10415, &diam.GroupedAVP{ // SMS-Information AVP: []*diam.AVP{ diam.NewAVP(886, avp.Mbit, 10415, &diam.GroupedAVP{ // Originator-Address AVP: []*diam.AVP{ diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1003")), // Address-Data }}), diam.NewAVP(1201, avp.Mbit, 10415, &diam.GroupedAVP{ // Recipient-Address AVP: []*diam.AVP{ diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1002")), // Address-Data }}), }, }), }}) ccr.NewAVP("Multiple-Services-Credit-Control", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(446, avp.Mbit, 0, &diam.GroupedAVP{ // Used-Service-Unit AVP: []*diam.AVP{ diam.NewAVP(452, avp.Mbit, 0, datatype.Enumerated(0)), // Tariff-Change-Usage diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(20)), // CC-Time diam.NewAVP(412, avp.Mbit, 0, datatype.Unsigned64(512)), // CC-Input-Octets diam.NewAVP(414, avp.Mbit, 0, datatype.Unsigned64(0)), // CC-Output-Octets }, }), }, }) if err := dmtClient.SendMessage(ccr); err != nil { t.Error(err) } time.Sleep(time.Duration(3000) * time.Millisecond) msg := dmtClient.ReceivedMessage(rplyTimeout) if msg == nil { t.Fatal("No message returned") } if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil { t.Error(err) } else if len(avps) == 0 { t.Error("Result-Code not found") } else if resCode := avpValAsString(avps[0]); resCode != "2001" { t.Errorf("Expecting 2001, received: %s", resCode) } }
func TestDmtAgentDryRun1(t *testing.T) { ccr := diam.NewRequest(diam.CreditControl, 4, nil) ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("cgrates;1451911932;00082")) ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA")) ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org")) ccr.NewAVP(avp.DestinationRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org")) ccr.NewAVP(avp.DestinationHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA")) ccr.NewAVP(avp.UserName, avp.Mbit, 0, datatype.UTF8String("CGR-DA")) ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)) ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("pubsub1")) // Match specific DryRun profile ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(2)) ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(1)) ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2016, 1, 5, 11, 30, 10, 0, time.UTC))) ccr.NewAVP(avp.TerminationCause, avp.Mbit, 0, datatype.Enumerated(1)) ccr.NewAVP(443, avp.Mbit, 0, &diam.GroupedAVP{ // Subscription-Id AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data }}) ccr.NewAVP(443, avp.Mbit, 0, &diam.GroupedAVP{ // Subscription-Id AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(1)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208123456789")), // Subscription-Id-Data }}) ccr.NewAVP(439, avp.Mbit, 0, datatype.Unsigned32(0)) // Service-Identifier ccr.NewAVP(437, avp.Mbit, 0, &diam.GroupedAVP{ // Requested-Service-Unit AVP: []*diam.AVP{ diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(300)), // CC-Time }}) ccr.NewAVP(873, avp.Mbit|avp.Vbit, 10415, &diam.GroupedAVP{ // Service-information AVP: []*diam.AVP{ diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information AVP: []*diam.AVP{ diam.NewAVP(20336, avp.Mbit, 2011, datatype.UTF8String("1001")), // CallingPartyAdress diam.NewAVP(20337, avp.Mbit, 2011, datatype.UTF8String("1002")), // CalledPartyAdress diam.NewAVP(20339, avp.Mbit, 2011, datatype.Unsigned32(0)), // ChargeFlowType diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("33609004940")), // CallingVlrNumber diam.NewAVP(20303, avp.Mbit, 2011, datatype.UTF8String("208104941749984")), // CallingCellID diam.NewAVP(20313, avp.Mbit, 2011, datatype.OctetString("0x8090a3")), // BearerCapability diam.NewAVP(20321, avp.Mbit, 2011, datatype.OctetString("0x401c4132ed665")), // CallreferenceNumber diam.NewAVP(20322, avp.Mbit, 2011, datatype.UTF8String("33609004940")), // MSCAddress diam.NewAVP(20386, avp.Mbit, 2011, datatype.UTF8String("20160501010101")), // SSPTime diam.NewAVP(20938, avp.Mbit, 2011, datatype.OctetString("0x00000001")), // HighLayerCharacteristics diam.NewAVP(20324, avp.Mbit, 2011, datatype.Integer32(8)), // Time-Zone }, }), }}) if _, err := ccr.NewAVP("Framed-IP-Address", avp.Mbit, 0, datatype.UTF8String("10.228.16.4")); err != nil { t.Error(err) } for i := 0; i < *interations; i++ { if err := dmtClient.SendMessage(ccr); err != nil { t.Error(err) } msg := dmtClient.ReceivedMessage(rplyTimeout) if msg == nil { t.Fatal("No message returned") } /* if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil { t.Error(err) } else if len(avps) == 0 { t.Error("Result-Code") } else if strResult := avpValAsString(avps[0]); strResult != "300" { // Result-Code set in the template t.Errorf("Expecting 300, received: %s", strResult) } */ } }
func BenchmarkEncodeAVP(b *testing.B) { a := NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("client")) for n := 0; n < b.N; n++ { a.Serialize() } }
// Used when sending from client to agent func (self *CCR) AsDiameterMessage() (*diam.Message, error) { m := diam.NewRequest(diam.CreditControl, 4, nil) if _, err := m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String(self.SessionId)); err != nil { return nil, err } if _, err := m.NewAVP("Origin-Host", avp.Mbit, 0, datatype.DiameterIdentity(self.OriginHost)); err != nil { return nil, err } if _, err := m.NewAVP("Origin-Realm", avp.Mbit, 0, datatype.DiameterIdentity(self.OriginRealm)); err != nil { return nil, err } if _, err := m.NewAVP("Destination-Host", avp.Mbit, 0, datatype.DiameterIdentity(self.DestinationHost)); err != nil { return nil, err } if _, err := m.NewAVP("Destination-Realm", avp.Mbit, 0, datatype.DiameterIdentity(self.DestinationRealm)); err != nil { return nil, err } if _, err := m.NewAVP("Auth-Application-Id", avp.Mbit, 0, datatype.Unsigned32(self.AuthApplicationId)); err != nil { return nil, err } if _, err := m.NewAVP("Service-Context-Id", avp.Mbit, 0, datatype.UTF8String(self.ServiceContextId)); err != nil { return nil, err } if _, err := m.NewAVP("CC-Request-Type", avp.Mbit, 0, datatype.Enumerated(self.CCRequestType)); err != nil { return nil, err } if _, err := m.NewAVP("CC-Request-Number", avp.Mbit, 0, datatype.Enumerated(self.CCRequestNumber)); err != nil { return nil, err } if _, err := m.NewAVP("Event-Timestamp", avp.Mbit, 0, datatype.Time(self.EventTimestamp)); err != nil { return nil, err } subscriptionIdType, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Subscription-Id-Type") if err != nil { return nil, err } subscriptionIdData, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Subscription-Id-Data") if err != nil { return nil, err } for _, subscriptionId := range self.SubscriptionId { if _, err := m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(subscriptionIdType.Code, avp.Mbit, 0, datatype.Enumerated(subscriptionId.SubscriptionIdType)), diam.NewAVP(subscriptionIdData.Code, avp.Mbit, 0, datatype.UTF8String(subscriptionId.SubscriptionIdData)), }}); err != nil { return nil, err } } if _, err := m.NewAVP("Service-Identifier", avp.Mbit, 0, datatype.Unsigned32(self.ServiceIdentifier)); err != nil { return nil, err } ccTimeAvp, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "CC-Time") if err != nil { return nil, err } if _, err := m.NewAVP("Requested-Service-Unit", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(ccTimeAvp.Code, avp.Mbit, 0, datatype.Unsigned32(self.RequestedServiceUnit.CCTime))}}); err != nil { return nil, err } inInformation, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "IN-Information") if err != nil { return nil, err } callingPartyAddress, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Calling-Party-Address") if err != nil { return nil, err } calledPartyAddress, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Called-Party-Address") if err != nil { return nil, err } realCalledNumber, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Real-Called-Number") if err != nil { return nil, err } chargeFlowType, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Charge-Flow-Type") if err != nil { return nil, err } callingVlrNumber, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Calling-Vlr-Number") if err != nil { return nil, err } callingCellIdOrSai, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Calling-CellID-Or-SAI") if err != nil { return nil, err } bearerCapability, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Bearer-Capability") if err != nil { return nil, err } callReferenceNumber, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Call-Reference-Number") if err != nil { return nil, err } mscAddress, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "MSC-Address") if err != nil { return nil, err } timeZone, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Time-Zone") if err != nil { return nil, err } calledPartyNP, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "Called-Party-NP") if err != nil { return nil, err } sspTime, err := m.Dictionary().FindAVP(m.Header.ApplicationID, "SSP-Time") if err != nil { return nil, err } if _, err := m.NewAVP("Service-Information", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(inInformation.Code, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(callingPartyAddress.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.CallingPartyAddress)), diam.NewAVP(calledPartyAddress.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.CalledPartyAddress)), diam.NewAVP(realCalledNumber.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.RealCalledNumber)), diam.NewAVP(chargeFlowType.Code, avp.Mbit, 0, datatype.Unsigned32(self.ServiceInformation.INInformation.ChargeFlowType)), diam.NewAVP(callingVlrNumber.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.CallingVlrNumber)), diam.NewAVP(callingCellIdOrSai.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.CallingCellIDOrSAI)), diam.NewAVP(bearerCapability.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.BearerCapability)), diam.NewAVP(callReferenceNumber.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.CallReferenceNumber)), diam.NewAVP(mscAddress.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.MSCAddress)), diam.NewAVP(timeZone.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.TimeZone)), diam.NewAVP(calledPartyNP.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.CalledPartyNP)), diam.NewAVP(sspTime.Code, avp.Mbit, 0, datatype.UTF8String(self.ServiceInformation.INInformation.SSPTime)), }, }), }}); err != nil { return nil, err } return m, nil }