ef27530e14491858efea0884c01815d4d988f98b
[ric-plt/submgr.git] / pkg / control / control.go
1 /*
2 ==================================================================================
3   Copyright (c) 2019 AT&T Intellectual Property.
4   Copyright (c) 2019 Nokia
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20 package control
21
22 import (
23         "fmt"
24         "gerrit.o-ran-sc.org/r/ric-plt/e2ap/pkg/e2ap"
25         rtmgrclient "gerrit.o-ran-sc.org/r/ric-plt/submgr/pkg/rtmgr_client"
26         rtmgrhandle "gerrit.o-ran-sc.org/r/ric-plt/submgr/pkg/rtmgr_client/handle"
27         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
28         httptransport "github.com/go-openapi/runtime/client"
29         "github.com/go-openapi/strfmt"
30         "github.com/spf13/viper"
31         "math/rand"
32         "sync"
33         "time"
34 )
35
36 //-----------------------------------------------------------------------------
37 //
38 //-----------------------------------------------------------------------------
39
40 var subReqTime time.Duration = 5 * time.Second
41 var subDelReqTime time.Duration = 5 * time.Second
42 var maxSubReqTryCount uint64 = 2    // Initial try + retry
43 var maxSubDelReqTryCount uint64 = 2 // Initial try + retry
44
45 type Control struct {
46         e2ap         *E2ap
47         registry     *Registry
48         tracker      *Tracker
49         timerMap     *TimerMap
50         rmrSendMutex sync.Mutex
51         msgCounter   uint64
52 }
53
54 type RMRMeid struct {
55         PlmnID  string
56         EnbID   string
57         RanName string
58 }
59
60 var seedSN uint16
61
62 const (
63         CREATE Action = 0
64         MERGE  Action = 1
65         NONE   Action = 2
66         DELETE Action = 3
67 )
68
69 func init() {
70         xapp.Logger.Info("SUBMGR")
71         viper.AutomaticEnv()
72         viper.SetEnvPrefix("submgr")
73         viper.AllowEmptyEnv(true)
74         seedSN = uint16(viper.GetInt("seed_sn"))
75         if seedSN == 0 {
76                 rand.Seed(time.Now().UnixNano())
77                 seedSN = uint16(rand.Intn(65535))
78         }
79         if seedSN > 65535 {
80                 seedSN = 0
81         }
82         xapp.Logger.Info("SUBMGR: Initial Sequence Number: %v", seedSN)
83 }
84
85 func NewControl() *Control {
86
87         transport := httptransport.New(viper.GetString("rtmgr.HostAddr")+":"+viper.GetString("rtmgr.port"), viper.GetString("rtmgr.baseUrl"), []string{"http"})
88         client := rtmgrclient.New(transport, strfmt.Default)
89         handle := rtmgrhandle.NewProvideXappSubscriptionHandleParamsWithTimeout(10 * time.Second)
90         deleteHandle := rtmgrhandle.NewDeleteXappSubscriptionHandleParamsWithTimeout(10 * time.Second)
91         rtmgrClient := RtmgrClient{client, handle, deleteHandle}
92
93         registry := new(Registry)
94         registry.Initialize(seedSN)
95         registry.rtmgrClient = &rtmgrClient
96
97         tracker := new(Tracker)
98         tracker.Init()
99
100         timerMap := new(TimerMap)
101         timerMap.Init()
102
103         return &Control{e2ap: new(E2ap),
104                 registry:   registry,
105                 tracker:    tracker,
106                 timerMap:   timerMap,
107                 msgCounter: 0,
108         }
109 }
110
111 func (c *Control) Run() {
112         xapp.Run(c)
113 }
114
115 func (c *Control) rmrSendRaw(desc string, params *RMRParams) (err error) {
116
117         xapp.Logger.Info("%s: %s", desc, params.String())
118         status := false
119         i := 1
120         for ; i <= 10 && status == false; i++ {
121                 c.rmrSendMutex.Lock()
122                 status = xapp.Rmr.Send(params.RMRParams, false)
123                 c.rmrSendMutex.Unlock()
124                 if status == false {
125                         xapp.Logger.Info("rmr.Send() failed. Retry count %d, %s", i, params.String())
126                         time.Sleep(500 * time.Millisecond)
127                 }
128         }
129         if status == false {
130                 err = fmt.Errorf("rmr.Send() failed. Retry count %d, %s", i, params.String())
131                 xapp.Logger.Error("%s: %s", desc, err.Error())
132                 xapp.Rmr.Free(params.Mbuf)
133         }
134         return
135 }
136
137 func (c *Control) rmrSend(desc string, subs *Subscription, trans *Transaction) (err error) {
138         params := &RMRParams{&xapp.RMRParams{}}
139         params.Mtype = trans.GetMtype()
140         params.SubId = int(subs.GetSubId())
141         params.Xid = ""
142         params.Meid = subs.GetMeid()
143         params.Src = ""
144         params.PayloadLen = len(trans.Payload.Buf)
145         params.Payload = trans.Payload.Buf
146         params.Mbuf = nil
147
148         return c.rmrSendRaw(desc, params)
149 }
150
151 func (c *Control) rmrReplyToSender(desc string, subs *Subscription, trans *Transaction) (err error) {
152         params := &RMRParams{&xapp.RMRParams{}}
153         params.Mtype = trans.GetMtype()
154         params.SubId = int(subs.GetSubId())
155         params.Xid = trans.GetXid()
156         params.Meid = trans.GetMeid()
157         params.Src = ""
158         params.PayloadLen = len(trans.Payload.Buf)
159         params.Payload = trans.Payload.Buf
160         params.Mbuf = nil
161
162         return c.rmrSendRaw(desc, params)
163 }
164
165 func (c *Control) Consume(params *xapp.RMRParams) (err error) {
166         xapp.Rmr.Free(params.Mbuf)
167         params.Mbuf = nil
168         msg := &RMRParams{params}
169         c.msgCounter++
170         switch msg.Mtype {
171         case xapp.RICMessageTypes["RIC_SUB_REQ"]:
172                 go c.handleSubscriptionRequest(msg)
173         case xapp.RICMessageTypes["RIC_SUB_RESP"]:
174                 go c.handleSubscriptionResponse(msg)
175         case xapp.RICMessageTypes["RIC_SUB_FAILURE"]:
176                 go c.handleSubscriptionFailure(msg)
177         case xapp.RICMessageTypes["RIC_SUB_DEL_REQ"]:
178                 go c.handleSubscriptionDeleteRequest(msg)
179         case xapp.RICMessageTypes["RIC_SUB_DEL_RESP"]:
180                 go c.handleSubscriptionDeleteResponse(msg)
181         case xapp.RICMessageTypes["RIC_SUB_DEL_FAILURE"]:
182                 go c.handleSubscriptionDeleteFailure(msg)
183         default:
184                 xapp.Logger.Info("Unknown Message Type '%d', discarding", msg.Mtype)
185         }
186
187         return nil
188 }
189
190 func (c *Control) handleSubscriptionRequest(params *RMRParams) {
191         xapp.Logger.Info("SubReq from xapp: %s", params.String())
192
193         //
194         //
195         //
196         trans, err := c.tracker.TrackTransaction(NewRmrEndpoint(params.Src),
197                 params.Xid,
198                 params.Meid,
199                 false,
200                 true)
201
202         if err != nil {
203                 xapp.Logger.Error("SubReq: %s, Dropping this msg. %s", err.Error(), params.String())
204                 return
205         }
206
207         //
208         //
209         //
210         trans.SubReqMsg, err = c.e2ap.UnpackSubscriptionRequest(params.Payload)
211         if err != nil {
212                 xapp.Logger.Error("SubReq: %s Dropping this msg. %s", err.Error(), trans)
213                 trans.Release()
214                 return
215         }
216
217         //
218         //
219         //
220         subs, err := c.registry.ReserveSubscription(&trans.RmrEndpoint, trans.Meid)
221         if err != nil {
222                 xapp.Logger.Error("SubReq: %s, Dropping this msg. %s", err.Error(), trans)
223                 trans.Release()
224                 return
225         }
226
227         err = subs.SetTransaction(trans)
228         if err != nil {
229                 xapp.Logger.Error("SubReq: %s, Dropping this msg. %s", err.Error(), trans)
230                 subs.Release()
231                 trans.Release()
232                 return
233         }
234
235         trans.SubReqMsg.RequestId.Seq = uint32(subs.GetSubId())
236
237         //
238         // TODO: subscription create is in fact owned by subscription and not transaction.
239         //       Transaction is toward xapp while Subscription is toward ran.
240         //       In merge several xapps may wake transactions, while only one subscription
241         //       toward ran occurs -> subscription owns subscription creation toward ran
242         //
243         //       This is intermediate solution while improving message handling
244         //
245         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionRequest(trans.SubReqMsg)
246         if err != nil {
247                 xapp.Logger.Error("SubReq: %s for trans %s", err.Error(), trans)
248                 subs.Release()
249                 trans.Release()
250                 return
251         }
252
253         c.rmrSend("SubReq: SubReq to E2T", subs, trans)
254
255         c.timerMap.StartTimer("RIC_SUB_REQ", int(subs.GetSubId()), subReqTime, FirstTry, c.handleSubscriptionRequestTimer)
256         xapp.Logger.Debug("SubReq: Debugging trans table = %v", c.tracker.transactionXappTable)
257         return
258 }
259
260 func (c *Control) handleSubscriptionResponse(params *RMRParams) {
261         xapp.Logger.Info("SubResp from E2T: %s", params.String())
262
263         //
264         //
265         //
266         SubRespMsg, err := c.e2ap.UnpackSubscriptionResponse(params.Payload)
267         if err != nil {
268                 xapp.Logger.Error("SubResp: %s Dropping this msg. %s", err.Error(), params.String())
269                 return
270         }
271
272         //
273         //
274         //
275         subs := c.registry.GetSubscription(uint16(SubRespMsg.RequestId.Seq))
276         if subs == nil && params.SubId > 0 {
277                 subs = c.registry.GetSubscription(uint16(params.SubId))
278         }
279
280         if subs == nil {
281                 xapp.Logger.Error("SubResp: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", SubRespMsg.RequestId.Seq, params.SubId, params.String())
282                 return
283         }
284         xapp.Logger.Info("SubResp: subscription found payloadSeqNum: %d, SubId: %d", SubRespMsg.RequestId.Seq, subs.GetSubId())
285
286         //
287         //
288         //
289         trans := subs.GetTransaction()
290         if trans == nil {
291                 xapp.Logger.Error("SubResp: Unknown trans. Dropping this msg. SubId: %d", subs.GetSubId())
292                 return
293         }
294
295         trans.SubRespMsg = SubRespMsg
296
297         //
298         //
299         //
300         c.timerMap.StopTimer("RIC_SUB_REQ", int(subs.GetSubId()))
301
302         responseReceived := trans.CheckResponseReceived()
303         if responseReceived == true {
304                 // Subscription timer already received
305                 return
306         }
307
308         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionResponse(trans.SubRespMsg)
309         if err != nil {
310                 xapp.Logger.Error("SubResp: %s for trans %s", err.Error(), trans)
311                 trans.Release()
312                 return
313         }
314
315         subs.Confirmed()
316         trans.Release()
317         c.rmrReplyToSender("SubResp: SubResp to xapp", subs, trans)
318         return
319 }
320
321 func (c *Control) handleSubscriptionFailure(params *RMRParams) {
322         xapp.Logger.Info("SubFail from E2T: %s", params.String())
323
324         //
325         //
326         //
327         SubFailMsg, err := c.e2ap.UnpackSubscriptionFailure(params.Payload)
328         if err != nil {
329                 xapp.Logger.Error("SubFail: %s Dropping this msg. %s", err.Error(), params.String())
330                 return
331         }
332
333         //
334         //
335         //
336         subs := c.registry.GetSubscription(uint16(SubFailMsg.RequestId.Seq))
337         if subs == nil && params.SubId > 0 {
338                 subs = c.registry.GetSubscription(uint16(params.SubId))
339         }
340
341         if subs == nil {
342                 xapp.Logger.Error("SubFail: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", SubFailMsg.RequestId.Seq, params.SubId, params.String())
343                 return
344         }
345         xapp.Logger.Info("SubFail: subscription found payloadSeqNum: %d, SubId: %d", SubFailMsg.RequestId.Seq, subs.GetSubId())
346
347         //
348         //
349         //
350         trans := subs.GetTransaction()
351         if trans == nil {
352                 xapp.Logger.Error("SubFail: Unknown trans. Dropping this msg. SubId: %d", subs.GetSubId())
353                 return
354         }
355         trans.SubFailMsg = SubFailMsg
356
357         //
358         //
359         //
360         c.timerMap.StopTimer("RIC_SUB_REQ", int(subs.GetSubId()))
361
362         responseReceived := trans.CheckResponseReceived()
363         if err != nil {
364                 return
365         }
366
367         if responseReceived == true {
368                 // Subscription timer already received
369                 return
370         }
371
372         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionFailure(trans.SubFailMsg)
373         if err == nil {
374                 c.rmrReplyToSender("SubFail: SubFail to xapp", subs, trans)
375                 time.Sleep(3 * time.Second)
376         } else {
377                 //TODO error handling improvement
378                 xapp.Logger.Error("SubFail: %s for trans %s (continuing cleaning)", err.Error(), trans)
379         }
380
381         trans.Release()
382         subs.Release()
383         return
384 }
385
386 func (c *Control) handleSubscriptionRequestTimer(strId string, nbrId int, tryCount uint64) {
387         xapp.Logger.Info("SubReq timeout: subId: %v,  tryCount: %v", nbrId, tryCount)
388
389         subs := c.registry.GetSubscription(uint16(nbrId))
390         if subs == nil {
391                 xapp.Logger.Error("SubReq timeout: Unknown payloadSeqNum. Dropping this msg. SubId: %v", nbrId)
392                 return
393         }
394
395         trans := subs.GetTransaction()
396         if trans == nil {
397                 xapp.Logger.Error("SubReq timeout: Unknown trans. Dropping this msg. SubId: %v", subs.GetSubId())
398                 return
399         }
400
401         responseReceived := trans.CheckResponseReceived()
402
403         if responseReceived == true {
404                 // Subscription Response or Failure already received
405                 return
406         }
407
408         if tryCount < maxSubReqTryCount {
409                 xapp.Logger.Info("SubReq timeout: subs: %s trans: %s", subs, trans)
410
411                 trans.RetryTransaction()
412
413                 c.rmrSend("SubReq timeout: SubReq to E2T", subs, trans)
414
415                 tryCount++
416                 c.timerMap.StartTimer("RIC_SUB_REQ", int(subs.GetSubId()), subReqTime, tryCount, c.handleSubscriptionRequestTimer)
417                 return
418         }
419
420         // Release CREATE transaction
421         trans.Release()
422
423         // Create DELETE transaction (internal and no messages toward xapp)
424         deltrans, err := c.tracker.TrackTransaction(&trans.RmrEndpoint,
425                 trans.GetXid(),
426                 trans.GetMeid(),
427                 false,
428                 false)
429
430         if err != nil {
431                 xapp.Logger.Error("SubReq timeout: %s, Dropping this msg.", err.Error())
432                 //TODO improve error handling. Important at least in merge
433                 subs.Release()
434                 return
435         }
436
437         deltrans.SubDelReqMsg = &e2ap.E2APSubscriptionDeleteRequest{}
438         deltrans.SubDelReqMsg.RequestId.Id = trans.SubReqMsg.RequestId.Id
439         deltrans.SubDelReqMsg.RequestId.Seq = uint32(subs.GetSubId())
440         deltrans.SubDelReqMsg.FunctionId = trans.SubReqMsg.FunctionId
441         deltrans.Mtype, deltrans.Payload, err = c.e2ap.PackSubscriptionDeleteRequest(deltrans.SubDelReqMsg)
442         if err != nil {
443                 xapp.Logger.Error("SubReq timeout: Packing SubDelReq failed. Err: %v", err)
444                 //TODO improve error handling. Important at least in merge
445                 deltrans.Release()
446                 subs.Release()
447                 return
448         }
449
450         err = subs.SetTransaction(deltrans)
451         if err != nil {
452                 xapp.Logger.Error("SubReq timeout: %s, Dropping this msg.", err.Error())
453                 //TODO improve error handling. Important at least in merge
454                 deltrans.Release()
455                 return
456         }
457
458         c.rmrSend("SubReq timer: SubDelReq to E2T", subs, deltrans)
459         c.timerMap.StartTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()), subDelReqTime, FirstTry, c.handleSubscriptionDeleteRequestTimer)
460         return
461 }
462
463 func (c *Control) handleSubscriptionDeleteRequest(params *RMRParams) {
464         xapp.Logger.Info("SubDelReq from xapp: %s", params.String())
465
466         //
467         //
468         //
469         trans, err := c.tracker.TrackTransaction(NewRmrEndpoint(params.Src),
470                 params.Xid,
471                 params.Meid,
472                 false,
473                 true)
474
475         if err != nil {
476                 xapp.Logger.Error("SubDelReq: %s, Dropping this msg. %s", err.Error(), params.String())
477                 return
478         }
479
480         //
481         //
482         //
483         trans.SubDelReqMsg, err = c.e2ap.UnpackSubscriptionDeleteRequest(params.Payload)
484         if err != nil {
485                 xapp.Logger.Error("SubDelReq: %s Dropping this msg. %s", err.Error(), trans)
486                 trans.Release()
487                 return
488         }
489
490         //
491         //
492         //
493         subs := c.registry.GetSubscription(uint16(trans.SubDelReqMsg.RequestId.Seq))
494         if subs == nil && params.SubId > 0 {
495                 subs = c.registry.GetSubscription(uint16(params.SubId))
496         }
497
498         if subs == nil {
499                 xapp.Logger.Error("SubDelReq: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", trans.SubDelReqMsg.RequestId.Seq, params.SubId, trans)
500                 trans.Release()
501                 return
502         }
503         xapp.Logger.Info("SubDelReq: subscription found payloadSeqNum: %d, SubId: %d. %s", trans.SubDelReqMsg.RequestId.Seq, params.SubId, trans)
504
505         err = subs.SetTransaction(trans)
506         if err != nil {
507                 xapp.Logger.Error("SubDelReq: %s, Dropping this msg. %s", err.Error(), trans)
508                 trans.Release()
509                 return
510         }
511
512         //
513         // TODO: subscription delete is in fact owned by subscription and not transaction.
514         //       Transaction is toward xapp while Subscription is toward ran.
515         //       In merge several xapps may wake transactions, while only one subscription
516         //       toward ran occurs -> subscription owns subscription creation toward ran
517         //
518         //       This is intermediate solution while improving message handling
519         //
520         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionDeleteRequest(trans.SubDelReqMsg)
521         if err != nil {
522                 xapp.Logger.Error("SubDelReq: %s for trans %s", err.Error(), trans)
523                 trans.Release()
524                 return
525         }
526
527         subs.UnConfirmed()
528
529         c.rmrSend("SubDelReq: SubDelReq to E2T", subs, trans)
530
531         c.timerMap.StartTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()), subDelReqTime, FirstTry, c.handleSubscriptionDeleteRequestTimer)
532         return
533 }
534
535 func (c *Control) handleSubscriptionDeleteResponse(params *RMRParams) (err error) {
536         xapp.Logger.Info("SubDelResp from E2T:%s", params.String())
537
538         //
539         //
540         //
541         SubDelRespMsg, err := c.e2ap.UnpackSubscriptionDeleteResponse(params.Payload)
542         if err != nil {
543                 xapp.Logger.Error("SubDelResp: %s Dropping this msg. %s", err.Error(), params.String())
544                 return
545         }
546
547         //
548         //
549         //
550         subs := c.registry.GetSubscription(uint16(SubDelRespMsg.RequestId.Seq))
551         if subs == nil && params.SubId > 0 {
552                 subs = c.registry.GetSubscription(uint16(params.SubId))
553         }
554
555         if subs == nil {
556                 xapp.Logger.Error("SubDelResp: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", SubDelRespMsg.RequestId.Seq, params.SubId, params.String())
557                 return
558         }
559         xapp.Logger.Info("SubDelResp: subscription found payloadSeqNum: %d, SubId: %d", SubDelRespMsg.RequestId.Seq, subs.GetSubId())
560
561         //
562         //
563         //
564         trans := subs.GetTransaction()
565         if trans == nil {
566                 xapp.Logger.Error("SubDelResp: Unknown trans. Dropping this msg. SubId: %d", subs.GetSubId())
567                 return
568         }
569
570         trans.SubDelRespMsg = SubDelRespMsg
571
572         //
573         //
574         //
575         c.timerMap.StopTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()))
576
577         responseReceived := trans.CheckResponseReceived()
578         if responseReceived == true {
579                 // Subscription Delete timer already received
580                 return
581         }
582
583         c.sendSubscriptionDeleteResponse("SubDelResp", trans, subs)
584         return
585 }
586
587 func (c *Control) handleSubscriptionDeleteFailure(params *RMRParams) {
588         xapp.Logger.Info("SubDelFail from E2T:%s", params.String())
589
590         //
591         //
592         //
593         SubDelFailMsg, err := c.e2ap.UnpackSubscriptionDeleteFailure(params.Payload)
594         if err != nil {
595                 xapp.Logger.Error("SubDelFail: %s Dropping this msg. %s", err.Error(), params.String())
596                 return
597         }
598
599         //
600         //
601         //
602         subs := c.registry.GetSubscription(uint16(SubDelFailMsg.RequestId.Seq))
603         if subs == nil && params.SubId > 0 {
604                 subs = c.registry.GetSubscription(uint16(params.SubId))
605         }
606
607         if subs == nil {
608                 xapp.Logger.Error("SubDelFail: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", SubDelFailMsg.RequestId.Seq, params.SubId, params.String())
609                 return
610         }
611         xapp.Logger.Info("SubDelFail: subscription found payloadSeqNum: %d, SubId: %d", SubDelFailMsg.RequestId.Seq, subs.GetSubId())
612
613         //
614         //
615         //
616         trans := subs.GetTransaction()
617         if trans == nil {
618                 xapp.Logger.Error("SubDelFail: Unknown trans. Dropping this msg. SubId: %d", subs.GetSubId())
619                 return
620         }
621         trans.SubDelFailMsg = SubDelFailMsg
622
623         //
624         //
625         //
626         c.timerMap.StopTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()))
627
628         responseReceived := trans.CheckResponseReceived()
629         if responseReceived == true {
630                 // Subscription Delete timer already received
631                 return
632         }
633
634         c.sendSubscriptionDeleteResponse("SubDelFail", trans, subs)
635         return
636 }
637
638 func (c *Control) handleSubscriptionDeleteRequestTimer(strId string, nbrId int, tryCount uint64) {
639         xapp.Logger.Info("SubDelReq timeout: subId: %v, tryCount: %v", nbrId, tryCount)
640
641         subs := c.registry.GetSubscription(uint16(nbrId))
642         if subs == nil {
643                 xapp.Logger.Error("SubDelReq timeout: Unknown payloadSeqNum. Dropping this msg. SubId: %v", nbrId)
644                 return
645         }
646
647         trans := subs.GetTransaction()
648         if trans == nil {
649                 xapp.Logger.Error("SubDelReq timeout: Unknown trans. Dropping this msg. SubId: %v", subs.GetSubId())
650                 return
651         }
652
653         responseReceived := trans.CheckResponseReceived()
654         if responseReceived == true {
655                 // Subscription Delete Response or Failure already received
656                 return
657         }
658
659         if tryCount < maxSubDelReqTryCount {
660                 // Set possible to handle new response for the subId
661                 trans.RetryTransaction()
662                 c.rmrSend("SubDelReq timeout: SubDelReq to E2T", subs, trans)
663                 tryCount++
664                 c.timerMap.StartTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()), subReqTime, tryCount, c.handleSubscriptionDeleteRequestTimer)
665                 return
666         }
667
668         c.sendSubscriptionDeleteResponse("SubDelReq(timer)", trans, subs)
669         return
670 }
671
672 func (c *Control) sendSubscriptionDeleteResponse(desc string, trans *Transaction, subs *Subscription) {
673
674         if trans.ForwardRespToXapp == true {
675                 //Always generate SubDelResp
676                 trans.SubDelRespMsg = &e2ap.E2APSubscriptionDeleteResponse{}
677                 trans.SubDelRespMsg.RequestId.Id = trans.SubDelReqMsg.RequestId.Id
678                 trans.SubDelRespMsg.RequestId.Seq = uint32(subs.GetSubId())
679                 trans.SubDelRespMsg.FunctionId = trans.SubDelReqMsg.FunctionId
680
681                 var err error
682                 trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionDeleteResponse(trans.SubDelRespMsg)
683                 if err == nil {
684                         c.rmrReplyToSender(desc+": SubDelResp to xapp", subs, trans)
685                         time.Sleep(3 * time.Second)
686                 } else {
687                         //TODO error handling improvement
688                         xapp.Logger.Error("%s: %s for trans %s (continuing cleaning)", desc, err.Error(), trans)
689                 }
690         }
691
692         trans.Release()
693         subs.Release()
694 }