297ocsadapter

Форк
0
261 строка · 8.9 Кб
1
package client
2

3
import (
4
	"github.com/fiorix/go-diameter/v4/diam"
5
	"github.com/fiorix/go-diameter/v4/diam/avp"
6
	"github.com/fiorix/go-diameter/v4/diam/datatype"
7
	"github.com/fiorix/go-diameter/v4/diam/dict"
8
	"github.com/fiorix/go-diameter/v4/diam/sm"
9
	"github.com/fiorix/go-diameter/v4/diam/sm/smpeer"
10
	"istio.io/pkg/log"
11
	"net"
12
	"strconv"
13
	"time"
14
)
15

16
var mux *sm.StateMachine
17
var done = make(chan *diam.Message, 1000)
18
var cfg *sm.Settings
19
var conn diam.Conn
20

21
func GetUnits(ocsAddress string, applicationId string, requestUnits []string, used int) int {
22
	createMux(ocsAddress)
23
	forceUpdate := false
24
	for i := range requestUnits {
25
		units, err := strconv.Atoi(requestUnits[i])
26
		if err != nil {
27
			log.Fatalf("Couldn't parse a value %v", requestUnits[0])
28
		}
29
		if used != 0 || forceUpdate {
30
			sendCCRU(applicationId, used, units)
31
		} else {
32
			sendCCRI(applicationId, units)
33
		}
34
		select {
35
		case m := <-done:
36
			resultCodeAvp, err := m.FindAVP(avp.ResultCode, 0)
37
			if err != nil {
38
				log.Warnf("Couldn't find Result-Code AVP in response for %s", applicationId)
39
				return 0
40
			}
41
			resultCode := int(resultCodeAvp.Data.(datatype.Unsigned32))
42
			if resultCode == 4012 {
43
				used = 0
44
				forceUpdate = true
45
				continue
46
			}
47
			timeAvp, err := m.FindAVP(avp.CCTime, 0)
48
			if err != nil {
49
				log.Warnf("Couldn't find CC-Time AVP in response for %s", applicationId)
50
				return 0
51
			}
52
			grantedAmount := int(timeAvp.Data.(datatype.Unsigned32))
53
			log.Infof("grantedAmount: %v", grantedAmount)
54
			return grantedAmount
55
		case <-time.After(5 * time.Second):
56
			log.Fatalf("timeout: no hello answer received")
57
		}
58
	}
59
	return 0
60
}
61

62
func Terminate(usedMap map[string]int) {
63
	if conn == nil {
64
		return
65
	}
66
	for applicationId, used := range usedMap {
67
		sendCCRT(applicationId, used)
68
	}
69
}
70

71
func createMux(ocsAddress string) {
72
	if mux != nil && conn.RemoteAddr().String() == ocsAddress {
73
		return
74
	}
75
	host := "client"
76
	realm := "ocs-adapter"
77
	networkType := "tcp"
78

79
	cfg = &sm.Settings{
80
		OriginHost:       datatype.DiameterIdentity(host),
81
		OriginRealm:      datatype.DiameterIdentity(realm),
82
		VendorID:         13,
83
		ProductName:      "go-diameter",
84
		OriginStateID:    datatype.Unsigned32(time.Now().Unix()),
85
		FirmwareRevision: 1,
86
		HostIPAddresses: []datatype.Address{
87
			datatype.Address(net.ParseIP("127.0.0.1")),
88
		},
89
	}
90

91
	// Create the state machine (it's a diam.ServeMux) and client.
92
	mux = sm.New(cfg)
93

94
	cli := &sm.Client{
95
		Dict:               dict.Default,
96
		Handler:            mux,
97
		MaxRetransmits:     0,
98
		RetransmitInterval: time.Second,
99
		EnableWatchdog:     false,
100
		WatchdogInterval:   5 * time.Second,
101
		SupportedVendorID: []*diam.AVP{
102
			diam.NewAVP(avp.SupportedVendorID, avp.Mbit, 0, datatype.Unsigned32(10415)),
103
		},
104
		VendorSpecificApplicationID: []*diam.AVP{
105
			diam.NewAVP(avp.VendorSpecificApplicationID, avp.Mbit, 0, &diam.GroupedAVP{
106
				AVP: []*diam.AVP{
107
					diam.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)),
108
					diam.NewAVP(avp.VendorID, avp.Mbit, 0, datatype.Unsigned32(10415)),
109
				},
110
			}),
111
		},
112
	}
113

114
	// Set message handlers.
115
	mux.Handle(diam.CCA, handleCCA())
116

117
	// Print error reports.
118
	go printErrors(mux.ErrorReports())
119

120
	// Makes a persistent connection with back-off.
121
	c, err := cli.DialNetwork(networkType, ocsAddress)
122
	if err != nil {
123
		log.Fatalf(err.Error())
124
	}
125
	conn = c
126
}
127

128
func printErrors(ec <-chan *diam.ErrorReport) {
129
	for err := range ec {
130
		log.Fatalf(err.String())
131
	}
132
}
133

134
func sendCCRI(applicationId string, requestUnits int) {
135
	log.Infof("send CCR to %v", conn.RemoteAddr().String())
136
	meta, ok := smpeer.FromContext(conn.Context())
137
	if !ok {
138
		log.Fatalf("Client connection does not contain metadata")
139
	}
140
	subscriptionId, _ := strconv.ParseUint(applicationId, 10, 32)
141
	m := diam.NewRequest(diam.CreditControl, 4, dict.Default)
142
	m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
143
	m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(strconv.Itoa(0)))
144
	m.NewAVP(avp.OriginHost, avp.Mbit, 0, cfg.OriginHost)
145
	m.NewAVP(avp.OriginRealm, avp.Mbit, 0, cfg.OriginRealm)
146
	m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, meta.OriginRealm)
147
	m.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.OctetString("32251@3gpp.org"))
148
	m.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
149
		AVP: []*diam.AVP{
150
			diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Unsigned32(3)),
151
			diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.OctetString(applicationId)),
152
		},
153
	})
154
	m.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Unsigned32(time.Now().Unix()))
155
	m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Unsigned32(1))
156
	m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(0))
157
	m.NewAVP(avp.MultipleServicesCreditControl, avp.Mbit, 0, &diam.GroupedAVP{
158
		AVP: []*diam.AVP{
159
			diam.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(uint32(subscriptionId))),
160
			diam.NewAVP(avp.RatingGroup, avp.Mbit, 0, datatype.Unsigned32(0)),
161
			diam.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
162
				AVP: []*diam.AVP{
163
					diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(requestUnits)),
164
				},
165
			}),
166
		},
167
	})
168
	if _, err := m.WriteTo(conn); err != nil {
169
		log.Fatalf(err.Error())
170
	}
171
}
172

173
func sendCCRU(applicationId string, used int, requestUnits int) {
174
	log.Infof("send CCR to %v", conn.RemoteAddr().String())
175
	meta, ok := smpeer.FromContext(conn.Context())
176
	if !ok {
177
		log.Fatalf("Client connection does not contain metadata")
178
	}
179
	subscriptionId, _ := strconv.ParseUint(applicationId, 10, 32)
180
	m := diam.NewRequest(diam.CreditControl, 4, dict.Default)
181
	m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
182
	m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(strconv.Itoa(0)))
183
	m.NewAVP(avp.OriginHost, avp.Mbit, 0, cfg.OriginHost)
184
	m.NewAVP(avp.OriginRealm, avp.Mbit, 0, cfg.OriginRealm)
185
	m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, meta.OriginRealm)
186
	m.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.OctetString("32251@3gpp.org"))
187
	m.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
188
		AVP: []*diam.AVP{
189
			diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Unsigned32(3)),
190
			diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.OctetString(applicationId)),
191
		},
192
	})
193
	m.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Unsigned32(time.Now().Unix()))
194
	m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Unsigned32(2))
195
	m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(0))
196
	m.NewAVP(avp.MultipleServicesCreditControl, avp.Mbit, 0, &diam.GroupedAVP{
197
		AVP: []*diam.AVP{
198
			diam.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(uint32(subscriptionId))),
199
			diam.NewAVP(avp.RatingGroup, avp.Mbit, 0, datatype.Unsigned32(0)),
200
			diam.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
201
				AVP: []*diam.AVP{
202
					diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(used)),
203
				},
204
			}),
205
			diam.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
206
				AVP: []*diam.AVP{
207
					diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(requestUnits)),
208
				},
209
			}),
210
		},
211
	})
212
	if _, err := m.WriteTo(conn); err != nil {
213
		log.Fatalf(err.Error())
214
	}
215
}
216

217
func sendCCRT(applicationId string, used int) {
218
	log.Infof("send CCR to %v", conn.RemoteAddr().String())
219
	meta, ok := smpeer.FromContext(conn.Context())
220
	if !ok {
221
		log.Fatalf("Client connection does not contain metadata")
222
	}
223
	subscriptionId, _ := strconv.ParseUint(applicationId, 10, 32)
224
	m := diam.NewRequest(diam.CreditControl, 4, dict.Default)
225
	m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
226
	m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(strconv.Itoa(0)))
227
	m.NewAVP(avp.OriginHost, avp.Mbit, 0, cfg.OriginHost)
228
	m.NewAVP(avp.OriginRealm, avp.Mbit, 0, cfg.OriginRealm)
229
	m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, meta.OriginRealm)
230
	m.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.OctetString("32251@3gpp.org"))
231
	m.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
232
		AVP: []*diam.AVP{
233
			diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Unsigned32(3)),
234
			diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.OctetString(applicationId)),
235
		},
236
	})
237
	m.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Unsigned32(time.Now().Unix()))
238
	m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Unsigned32(3))
239
	m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(0))
240
	m.NewAVP(avp.MultipleServicesCreditControl, avp.Mbit, 0, &diam.GroupedAVP{
241
		AVP: []*diam.AVP{
242
			diam.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(uint32(subscriptionId))),
243
			diam.NewAVP(avp.RatingGroup, avp.Mbit, 0, datatype.Unsigned32(0)),
244
			diam.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
245
				AVP: []*diam.AVP{
246
					diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(used)),
247
				},
248
			}),
249
		},
250
	})
251
	if _, err := m.WriteTo(conn); err != nil {
252
		log.Fatalf(err.Error())
253
	}
254
}
255

256
func handleCCA() diam.HandlerFunc {
257
	return func(c diam.Conn, m *diam.Message) {
258
		log.Infof("Received CCA from %s\n%s", c.RemoteAddr(), m)
259
		done <- m
260
	}
261
}
262

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.