diff --git a/agents/dmtagent.go b/agents/dmtagent.go index d10224be1..50dc7ec0a 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -28,7 +28,6 @@ import ( "github.com/cgrates/cgrates/utils" "github.com/cgrates/rpcclient" "github.com/fiorix/go-diameter/diam" - //"github.com/fiorix/go-diameter/diam/avp" "github.com/fiorix/go-diameter/diam/datatype" "github.com/fiorix/go-diameter/diam/dict" "github.com/fiorix/go-diameter/diam/sm" diff --git a/agents/libdmt.go b/agents/libdmt.go new file mode 100644 index 000000000..87cc02ca0 --- /dev/null +++ b/agents/libdmt.go @@ -0,0 +1,120 @@ +/* +Real-time Charging System for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package agents + +/* +Build various type of packets here +*/ + +import ( + "math" + "math/rand" + "strconv" + "time" + + "github.com/cgrates/cgrates/engine" + "github.com/fiorix/go-diameter/diam" + "github.com/fiorix/go-diameter/diam/avp" + "github.com/fiorix/go-diameter/diam/datatype" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// Returns reqType, requestNr and ccTime in seconds +func disectUsageForCCR(usage time.Duration, debitInterval time.Duration, callEnded bool) (int, int, int) { + usageSecs := usage.Seconds() + debitIntervalSecs := debitInterval.Seconds() + reqType := 1 + if usage > 0 { + reqType = 2 + } + if callEnded { + reqType = 3 + } + reqNr := int(usageSecs / debitIntervalSecs) + if callEnded { + reqNr += 1 + } + ccTime := debitInterval.Seconds() + if callEnded { + ccTime = math.Mod(usageSecs, debitIntervalSecs) + } + return reqType, reqNr, int(ccTime) +} + +func getUsageFromCCR(reqType, reqNr, ccTime int, debitIterval time.Duration) time.Duration { + dISecs := debitIterval.Seconds() + if reqType == 3 { + reqNr -= 1 // decrease request number to reach the real number + } + ccTime += int(dISecs) * reqNr + return time.Duration(ccTime) * time.Second +} + +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("voice@huawei.com")) + 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 +} diff --git a/agents/libdmt_test.go b/agents/libdmt_test.go new file mode 100644 index 000000000..00d5864c8 --- /dev/null +++ b/agents/libdmt_test.go @@ -0,0 +1,61 @@ +/* +Real-time Charging System for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package agents + +import ( + "testing" + "time" +) + +func TestDisectUsageForCCR(t *testing.T) { + if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(0)*time.Second, time.Duration(300)*time.Second, false); reqType != 1 || reqNr != 0 || ccTime != 300 { + t.Error(reqType, reqNr, ccTime) + } + if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(35)*time.Second, time.Duration(300)*time.Second, false); reqType != 2 || reqNr != 0 || ccTime != 300 { + t.Error(reqType, reqNr, ccTime) + } + if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(935)*time.Second, time.Duration(300)*time.Second, false); reqType != 2 || reqNr != 3 || ccTime != 300 { + t.Error(reqType, reqNr, ccTime) + } + if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(35)*time.Second, time.Duration(300)*time.Second, true); reqType != 3 || reqNr != 1 || ccTime != 35 { + t.Error(reqType, reqNr, ccTime) + } + if reqType, reqNr, ccTime := disectUsageForCCR(time.Duration(935)*time.Second, time.Duration(300)*time.Second, true); reqType != 3 || reqNr != 4 || ccTime != 35 { + t.Error(reqType, reqNr, ccTime) + } + +} + +func TestGetUsageFromCCR(t *testing.T) { + if usage := getUsageFromCCR(1, 0, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + t.Error(usage) + } + if usage := getUsageFromCCR(2, 0, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + t.Error(usage) + } + if usage := getUsageFromCCR(2, 3, 300, time.Duration(300)*time.Second); usage != time.Duration(1200)*time.Second { + t.Error(usage) + } + if usage := getUsageFromCCR(3, 4, 35, time.Duration(300)*time.Second); usage != time.Duration(935)*time.Second { + t.Error(usage) + } + if usage := getUsageFromCCR(3, 1, 35, time.Duration(300)*time.Second); usage != time.Duration(35)*time.Second { + t.Error(usage) + } +}