Releasing current master branch
[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         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models"
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         "time"
32 )
33
34 //-----------------------------------------------------------------------------
35 //
36 //-----------------------------------------------------------------------------
37
38 func idstring(err error, entries ...fmt.Stringer) string {
39         var retval string = ""
40         var filler string = ""
41         for _, entry := range entries {
42                 retval += filler + entry.String()
43                 filler = " "
44         }
45         if err != nil {
46                 retval += filler + "err(" + err.Error() + ")"
47                 filler = " "
48
49         }
50         return retval
51 }
52
53 //-----------------------------------------------------------------------------
54 //
55 //-----------------------------------------------------------------------------
56
57 var e2tSubReqTimeout time.Duration = 5 * time.Second
58 var e2tSubDelReqTime time.Duration = 5 * time.Second
59 var e2tMaxSubReqTryCount uint64 = 2    // Initial try + retry
60 var e2tMaxSubDelReqTryCount uint64 = 2 // Initial try + retry
61
62 var e2tRecvMsgTimeout time.Duration = 5 * time.Second
63
64 type Control struct {
65         *xapp.RMRClient
66         e2ap     *E2ap
67         registry *Registry
68         tracker  *Tracker
69         //subscriber *xapp.Subscriber
70         CntRecvMsg uint64
71 }
72
73 type RMRMeid struct {
74         PlmnID  string
75         EnbID   string
76         RanName string
77 }
78
79 func init() {
80         xapp.Logger.Info("SUBMGR")
81         viper.AutomaticEnv()
82         viper.SetEnvPrefix("submgr")
83         viper.AllowEmptyEnv(true)
84 }
85
86 func NewControl() *Control {
87
88         transport := httptransport.New(viper.GetString("rtmgr.HostAddr")+":"+viper.GetString("rtmgr.port"), viper.GetString("rtmgr.baseUrl"), []string{"http"})
89         rtmgrClient := RtmgrClient{rtClient: rtmgrclient.New(transport, strfmt.Default)}
90
91         registry := new(Registry)
92         registry.Initialize()
93         registry.rtmgrClient = &rtmgrClient
94
95         tracker := new(Tracker)
96         tracker.Init()
97
98         //subscriber := xapp.NewSubscriber(viper.GetString("subscription.host"), viper.GetInt("subscription.timeout"))
99
100         c := &Control{e2ap: new(E2ap),
101                 registry: registry,
102                 tracker:  tracker,
103                 //subscriber: subscriber,
104         }
105         go xapp.Subscription.Listen(c.SubscriptionHandler, c.QueryHandler, c.SubscriptionDeleteHandler)
106         //go c.subscriber.Listen(c.SubscriptionHandler, c.QueryHandler)
107         return c
108 }
109
110 func (c *Control) ReadyCB(data interface{}) {
111         if c.RMRClient == nil {
112                 c.RMRClient = xapp.Rmr
113         }
114 }
115
116 func (c *Control) Run() {
117         xapp.SetReadyCB(c.ReadyCB, nil)
118         xapp.Run(c)
119 }
120
121 //-------------------------------------------------------------------
122 //
123 //-------------------------------------------------------------------
124 func (c *Control) SubscriptionHandler(stype models.SubscriptionType, params interface{}) (*models.SubscriptionResponse, error) {
125         /*
126            switch p := params.(type) {
127            case *models.ReportParams:
128                trans := c.tracker.NewXappTransaction(NewRmrEndpoint(p.ClientEndpoint),"" , 0, &xapp.RMRMeid{RanName: p.Meid})
129                if trans == nil {
130                      xapp.Logger.Error("XAPP-SubReq: %s", idstring(fmt.Errorf("transaction not created"), params))
131                      return
132                }
133                defer trans.Release()
134            case *models.ControlParams:
135            case *models.PolicyParams:
136            }
137         */
138         return &models.SubscriptionResponse{}, fmt.Errorf("Subscription rest interface not implemented")
139 }
140
141 func (c *Control) SubscriptionDeleteHandler(string) error {
142         return fmt.Errorf("Subscription rest interface not implemented")
143 }
144
145 func (c *Control) QueryHandler() (models.SubscriptionList, error) {
146         return c.registry.QueryHandler()
147 }
148
149 //-------------------------------------------------------------------
150 //
151 //-------------------------------------------------------------------
152
153 func (c *Control) rmrSendToE2T(desc string, subs *Subscription, trans *TransactionSubs) (err error) {
154         params := &xapp.RMRParams{}
155         params.Mtype = trans.GetMtype()
156         params.SubId = int(subs.GetReqId().InstanceId)
157         params.Xid = ""
158         params.Meid = subs.GetMeid()
159         params.Src = ""
160         params.PayloadLen = len(trans.Payload.Buf)
161         params.Payload = trans.Payload.Buf
162         params.Mbuf = nil
163         xapp.Logger.Info("MSG to E2T: %s %s %s", desc, trans.String(), params.String())
164         return c.SendWithRetry(params, false, 5)
165 }
166
167 func (c *Control) rmrSendToXapp(desc string, subs *Subscription, trans *TransactionXapp) (err error) {
168
169         params := &xapp.RMRParams{}
170         params.Mtype = trans.GetMtype()
171         params.SubId = int(subs.GetReqId().InstanceId)
172         params.Xid = trans.GetXid()
173         params.Meid = trans.GetMeid()
174         params.Src = ""
175         params.PayloadLen = len(trans.Payload.Buf)
176         params.Payload = trans.Payload.Buf
177         params.Mbuf = nil
178         xapp.Logger.Info("MSG to XAPP: %s %s %s", desc, trans.String(), params.String())
179         return c.SendWithRetry(params, false, 5)
180 }
181
182 func (c *Control) Consume(msg *xapp.RMRParams) (err error) {
183         if c.RMRClient == nil {
184                 err = fmt.Errorf("Rmr object nil can handle %s", msg.String())
185                 xapp.Logger.Error("%s", err.Error())
186                 return
187         }
188         c.CntRecvMsg++
189
190         defer c.RMRClient.Free(msg.Mbuf)
191
192         // xapp-frame might use direct access to c buffer and
193         // when msg.Mbuf is freed, someone might take it into use
194         // and payload data might be invalid inside message handle function
195         //
196         // subscriptions won't load system a lot so there is no
197         // real performance hit by cloning buffer into new go byte slice
198         cPay := append(msg.Payload[:0:0], msg.Payload...)
199         msg.Payload = cPay
200         msg.PayloadLen = len(cPay)
201
202         switch msg.Mtype {
203         case xapp.RIC_SUB_REQ:
204                 go c.handleXAPPSubscriptionRequest(msg)
205         case xapp.RIC_SUB_RESP:
206                 go c.handleE2TSubscriptionResponse(msg)
207         case xapp.RIC_SUB_FAILURE:
208                 go c.handleE2TSubscriptionFailure(msg)
209         case xapp.RIC_SUB_DEL_REQ:
210                 go c.handleXAPPSubscriptionDeleteRequest(msg)
211         case xapp.RIC_SUB_DEL_RESP:
212                 go c.handleE2TSubscriptionDeleteResponse(msg)
213         case xapp.RIC_SUB_DEL_FAILURE:
214                 go c.handleE2TSubscriptionDeleteFailure(msg)
215         default:
216                 xapp.Logger.Info("Unknown Message Type '%d', discarding", msg.Mtype)
217         }
218         return
219 }
220
221 //-------------------------------------------------------------------
222 // handle from XAPP Subscription Request
223 //------------------------------------------------------------------
224 func (c *Control) handleXAPPSubscriptionRequest(params *xapp.RMRParams) {
225         xapp.Logger.Info("MSG from XAPP: %s", params.String())
226
227         subReqMsg, err := c.e2ap.UnpackSubscriptionRequest(params.Payload)
228         if err != nil {
229                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, params))
230                 return
231         }
232
233         trans := c.tracker.NewXappTransaction(xapp.NewRmrEndpoint(params.Src), params.Xid, subReqMsg.RequestId.InstanceId, params.Meid)
234         if trans == nil {
235                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(fmt.Errorf("transaction not created"), params))
236                 return
237         }
238         defer trans.Release()
239
240         err = c.tracker.Track(trans)
241         if err != nil {
242                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, trans))
243                 return
244         }
245
246         //TODO handle subscription toward e2term inside AssignToSubscription / hide handleSubscriptionCreate in it?
247         subs, err := c.registry.AssignToSubscription(trans, subReqMsg)
248         if err != nil {
249                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, trans))
250                 return
251         }
252
253         //
254         // Wake subs request
255         //
256         go c.handleSubscriptionCreate(subs, trans)
257         event, _ := trans.WaitEvent(0) //blocked wait as timeout is handled in subs side
258
259         err = nil
260         if event != nil {
261                 switch themsg := event.(type) {
262                 case *e2ap.E2APSubscriptionResponse:
263                         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionResponse(themsg)
264                         if err == nil {
265                                 trans.Release()
266                                 c.rmrSendToXapp("", subs, trans)
267                                 return
268                         }
269                 case *e2ap.E2APSubscriptionFailure:
270                         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionFailure(themsg)
271                         if err == nil {
272                                 c.rmrSendToXapp("", subs, trans)
273                         }
274                 default:
275                         break
276                 }
277         }
278         xapp.Logger.Info("XAPP-SubReq: failed %s", idstring(err, trans, subs))
279         //c.registry.RemoveFromSubscription(subs, trans, 5*time.Second)
280 }
281
282 //-------------------------------------------------------------------
283 // handle from XAPP Subscription Delete Request
284 //------------------------------------------------------------------
285 func (c *Control) handleXAPPSubscriptionDeleteRequest(params *xapp.RMRParams) {
286         xapp.Logger.Info("MSG from XAPP: %s", params.String())
287
288         subDelReqMsg, err := c.e2ap.UnpackSubscriptionDeleteRequest(params.Payload)
289         if err != nil {
290                 xapp.Logger.Error("XAPP-SubDelReq %s", idstring(err, params))
291                 return
292         }
293
294         trans := c.tracker.NewXappTransaction(xapp.NewRmrEndpoint(params.Src), params.Xid, subDelReqMsg.RequestId.InstanceId, params.Meid)
295         if trans == nil {
296                 xapp.Logger.Error("XAPP-SubDelReq: %s", idstring(fmt.Errorf("transaction not created"), params))
297                 return
298         }
299         defer trans.Release()
300
301         err = c.tracker.Track(trans)
302         if err != nil {
303                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, trans))
304                 return
305         }
306
307         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{trans.GetSubId()})
308         if err != nil {
309                 xapp.Logger.Error("XAPP-SubDelReq: %s", idstring(err, trans))
310                 return
311         }
312
313         //
314         // Wake subs delete
315         //
316         go c.handleSubscriptionDelete(subs, trans)
317         trans.WaitEvent(0) //blocked wait as timeout is handled in subs side
318
319         xapp.Logger.Debug("XAPP-SubDelReq: Handling event %s ", idstring(nil, trans, subs))
320
321         // Whatever is received send ok delete response
322         subDelRespMsg := &e2ap.E2APSubscriptionDeleteResponse{}
323         subDelRespMsg.RequestId = subs.GetReqId().RequestId
324         subDelRespMsg.FunctionId = subs.SubReqMsg.FunctionId
325         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionDeleteResponse(subDelRespMsg)
326         if err == nil {
327                 c.rmrSendToXapp("", subs, trans)
328         }
329
330         //TODO handle subscription toward e2term insiged RemoveFromSubscription / hide handleSubscriptionDelete in it?
331         //c.registry.RemoveFromSubscription(subs, trans, 5*time.Second)
332 }
333
334 //-------------------------------------------------------------------
335 // SUBS CREATE Handling
336 //-------------------------------------------------------------------
337 func (c *Control) handleSubscriptionCreate(subs *Subscription, parentTrans *TransactionXapp) {
338
339         trans := c.tracker.NewSubsTransaction(subs)
340         subs.WaitTransactionTurn(trans)
341         defer subs.ReleaseTransactionTurn(trans)
342         defer trans.Release()
343
344         xapp.Logger.Debug("SUBS-SubReq: Handling %s ", idstring(nil, trans, subs, parentTrans))
345
346         subRfMsg, valid := subs.GetCachedResponse()
347         if subRfMsg == nil && valid == true {
348
349                 //
350                 // In case of failure
351                 // - make internal delete
352                 // - in case duplicate cause, retry (currently max 1 retry)
353                 //
354                 maxRetries := uint64(1)
355                 doRetry := true
356                 for retries := uint64(0); retries <= maxRetries && doRetry; retries++ {
357                         doRetry = false
358
359                         event := c.sendE2TSubscriptionRequest(subs, trans, parentTrans)
360                         switch themsg := event.(type) {
361                         case *e2ap.E2APSubscriptionResponse:
362                                 subRfMsg, valid = subs.SetCachedResponse(event, true)
363                         case *e2ap.E2APSubscriptionFailure:
364                                 subRfMsg, valid = subs.SetCachedResponse(event, false)
365                                 doRetry = true
366                                 for _, item := range themsg.ActionNotAdmittedList.Items {
367                                         if item.Cause.Content != e2ap.E2AP_CauseContent_Ric || (item.Cause.Value != e2ap.E2AP_CauseValue_Ric_duplicate_action && item.Cause.Value != e2ap.E2AP_CauseValue_Ric_duplicate_event) {
368                                                 doRetry = false
369                                                 break
370                                         }
371                                 }
372                                 xapp.Logger.Info("SUBS-SubReq: internal delete and possible retry due event(%s) retry(%t,%d/%d) %s", typeofSubsMessage(event), doRetry, retries, maxRetries, idstring(nil, trans, subs, parentTrans))
373                                 c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans)
374                         default:
375                                 xapp.Logger.Info("SUBS-SubReq: internal delete due event(%s) %s", typeofSubsMessage(event), idstring(nil, trans, subs, parentTrans))
376                                 subRfMsg, valid = subs.SetCachedResponse(nil, false)
377                                 c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans)
378                         }
379                 }
380
381                 xapp.Logger.Debug("SUBS-SubReq: Handling (e2t response %s) %s", typeofSubsMessage(subRfMsg), idstring(nil, trans, subs, parentTrans))
382         } else {
383                 xapp.Logger.Debug("SUBS-SubReq: Handling (cached response %s) %s", typeofSubsMessage(subRfMsg), idstring(nil, trans, subs, parentTrans))
384         }
385
386         //Now RemoveFromSubscription in here to avoid race conditions (mostly concerns delete)
387         if valid == false {
388                 c.registry.RemoveFromSubscription(subs, parentTrans, 5*time.Second)
389         }
390         parentTrans.SendEvent(subRfMsg, 0)
391 }
392
393 //-------------------------------------------------------------------
394 // SUBS DELETE Handling
395 //-------------------------------------------------------------------
396
397 func (c *Control) handleSubscriptionDelete(subs *Subscription, parentTrans *TransactionXapp) {
398
399         trans := c.tracker.NewSubsTransaction(subs)
400         subs.WaitTransactionTurn(trans)
401         defer subs.ReleaseTransactionTurn(trans)
402         defer trans.Release()
403
404         xapp.Logger.Debug("SUBS-SubDelReq: Handling %s", idstring(nil, trans, subs, parentTrans))
405
406         subs.mutex.Lock()
407         if subs.valid && subs.EpList.HasEndpoint(parentTrans.GetEndpoint()) && subs.EpList.Size() == 1 {
408                 subs.valid = false
409                 subs.mutex.Unlock()
410                 c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans)
411         } else {
412                 subs.mutex.Unlock()
413         }
414         //Now RemoveFromSubscription in here to avoid race conditions (mostly concerns delete)
415         //  If parallel deletes ongoing both might pass earlier sendE2TSubscriptionDeleteRequest(...) if
416         //  RemoveFromSubscription locates in caller side (now in handleXAPPSubscriptionDeleteRequest(...))
417         c.registry.RemoveFromSubscription(subs, parentTrans, 5*time.Second)
418         parentTrans.SendEvent(nil, 0)
419 }
420
421 //-------------------------------------------------------------------
422 // send to E2T Subscription Request
423 //-------------------------------------------------------------------
424 func (c *Control) sendE2TSubscriptionRequest(subs *Subscription, trans *TransactionSubs, parentTrans *TransactionXapp) interface{} {
425         var err error
426         var event interface{} = nil
427         var timedOut bool = false
428
429         subReqMsg := subs.SubReqMsg
430         subReqMsg.RequestId = subs.GetReqId().RequestId
431         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionRequest(subReqMsg)
432         if err != nil {
433                 xapp.Logger.Error("SUBS-SubReq: %s", idstring(err, trans, subs, parentTrans))
434                 return event
435         }
436
437         for retries := uint64(0); retries < e2tMaxSubReqTryCount; retries++ {
438                 desc := fmt.Sprintf("(retry %d)", retries)
439                 c.rmrSendToE2T(desc, subs, trans)
440                 event, timedOut = trans.WaitEvent(e2tSubReqTimeout)
441                 if timedOut {
442                         continue
443                 }
444                 break
445         }
446         xapp.Logger.Debug("SUBS-SubReq: Response handling event(%s) %s", typeofSubsMessage(event), idstring(nil, trans, subs, parentTrans))
447         return event
448 }
449
450 //-------------------------------------------------------------------
451 // send to E2T Subscription Delete Request
452 //-------------------------------------------------------------------
453
454 func (c *Control) sendE2TSubscriptionDeleteRequest(subs *Subscription, trans *TransactionSubs, parentTrans *TransactionXapp) interface{} {
455         var err error
456         var event interface{}
457         var timedOut bool
458
459         subDelReqMsg := &e2ap.E2APSubscriptionDeleteRequest{}
460         subDelReqMsg.RequestId = subs.GetReqId().RequestId
461         subDelReqMsg.FunctionId = subs.SubReqMsg.FunctionId
462         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionDeleteRequest(subDelReqMsg)
463         if err != nil {
464                 xapp.Logger.Error("SUBS-SubDelReq: %s", idstring(err, trans, subs, parentTrans))
465                 return event
466         }
467
468         for retries := uint64(0); retries < e2tMaxSubDelReqTryCount; retries++ {
469                 desc := fmt.Sprintf("(retry %d)", retries)
470                 c.rmrSendToE2T(desc, subs, trans)
471                 event, timedOut = trans.WaitEvent(e2tSubDelReqTime)
472                 if timedOut {
473                         continue
474                 }
475                 break
476         }
477         xapp.Logger.Debug("SUBS-SubDelReq: Response handling event(%s) %s", typeofSubsMessage(event), idstring(nil, trans, subs, parentTrans))
478         return event
479 }
480
481 //-------------------------------------------------------------------
482 // handle from E2T Subscription Reponse
483 //-------------------------------------------------------------------
484 func (c *Control) handleE2TSubscriptionResponse(params *xapp.RMRParams) {
485         xapp.Logger.Info("MSG from E2T: %s", params.String())
486         subRespMsg, err := c.e2ap.UnpackSubscriptionResponse(params.Payload)
487         if err != nil {
488                 xapp.Logger.Error("MSG-SubResp %s", idstring(err, params))
489                 return
490         }
491         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{subRespMsg.RequestId.InstanceId})
492         if err != nil {
493                 xapp.Logger.Error("MSG-SubResp: %s", idstring(err, params))
494                 return
495         }
496         trans := subs.GetTransaction()
497         if trans == nil {
498                 err = fmt.Errorf("Ongoing transaction not found")
499                 xapp.Logger.Error("MSG-SubResp: %s", idstring(err, params, subs))
500                 return
501         }
502         sendOk, timedOut := trans.SendEvent(subRespMsg, e2tRecvMsgTimeout)
503         if sendOk == false {
504                 err = fmt.Errorf("Passing event to transaction failed: sendOk(%t) timedOut(%t)", sendOk, timedOut)
505                 xapp.Logger.Error("MSG-SubResp: %s", idstring(err, trans, subs))
506         }
507         return
508 }
509
510 //-------------------------------------------------------------------
511 // handle from E2T Subscription Failure
512 //-------------------------------------------------------------------
513 func (c *Control) handleE2TSubscriptionFailure(params *xapp.RMRParams) {
514         xapp.Logger.Info("MSG from E2T: %s", params.String())
515         subFailMsg, err := c.e2ap.UnpackSubscriptionFailure(params.Payload)
516         if err != nil {
517                 xapp.Logger.Error("MSG-SubFail %s", idstring(err, params))
518                 return
519         }
520         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{subFailMsg.RequestId.InstanceId})
521         if err != nil {
522                 xapp.Logger.Error("MSG-SubFail: %s", idstring(err, params))
523                 return
524         }
525         trans := subs.GetTransaction()
526         if trans == nil {
527                 err = fmt.Errorf("Ongoing transaction not found")
528                 xapp.Logger.Error("MSG-SubFail: %s", idstring(err, params, subs))
529                 return
530         }
531         sendOk, timedOut := trans.SendEvent(subFailMsg, e2tRecvMsgTimeout)
532         if sendOk == false {
533                 err = fmt.Errorf("Passing event to transaction failed: sendOk(%t) timedOut(%t)", sendOk, timedOut)
534                 xapp.Logger.Error("MSG-SubFail: %s", idstring(err, trans, subs))
535         }
536         return
537 }
538
539 //-------------------------------------------------------------------
540 // handle from E2T Subscription Delete Response
541 //-------------------------------------------------------------------
542 func (c *Control) handleE2TSubscriptionDeleteResponse(params *xapp.RMRParams) (err error) {
543         xapp.Logger.Info("MSG from E2T: %s", params.String())
544         subDelRespMsg, err := c.e2ap.UnpackSubscriptionDeleteResponse(params.Payload)
545         if err != nil {
546                 xapp.Logger.Error("MSG-SubDelResp: %s", idstring(err, params))
547                 return
548         }
549         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{subDelRespMsg.RequestId.InstanceId})
550         if err != nil {
551                 xapp.Logger.Error("MSG-SubDelResp: %s", idstring(err, params))
552                 return
553         }
554         trans := subs.GetTransaction()
555         if trans == nil {
556                 err = fmt.Errorf("Ongoing transaction not found")
557                 xapp.Logger.Error("MSG-SubDelResp: %s", idstring(err, params, subs))
558                 return
559         }
560         sendOk, timedOut := trans.SendEvent(subDelRespMsg, e2tRecvMsgTimeout)
561         if sendOk == false {
562                 err = fmt.Errorf("Passing event to transaction failed: sendOk(%t) timedOut(%t)", sendOk, timedOut)
563                 xapp.Logger.Error("MSG-SubDelResp: %s", idstring(err, trans, subs))
564         }
565         return
566 }
567
568 //-------------------------------------------------------------------
569 // handle from E2T Subscription Delete Failure
570 //-------------------------------------------------------------------
571 func (c *Control) handleE2TSubscriptionDeleteFailure(params *xapp.RMRParams) {
572         xapp.Logger.Info("MSG from E2T: %s", params.String())
573         subDelFailMsg, err := c.e2ap.UnpackSubscriptionDeleteFailure(params.Payload)
574         if err != nil {
575                 xapp.Logger.Error("MSG-SubDelFail: %s", idstring(err, params))
576                 return
577         }
578         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{subDelFailMsg.RequestId.InstanceId})
579         if err != nil {
580                 xapp.Logger.Error("MSG-SubDelFail: %s", idstring(err, params))
581                 return
582         }
583         trans := subs.GetTransaction()
584         if trans == nil {
585                 err = fmt.Errorf("Ongoing transaction not found")
586                 xapp.Logger.Error("MSG-SubDelFail: %s", idstring(err, params, subs))
587                 return
588         }
589         sendOk, timedOut := trans.SendEvent(subDelFailMsg, e2tRecvMsgTimeout)
590         if sendOk == false {
591                 err = fmt.Errorf("Passing event to transaction failed: sendOk(%t) timedOut(%t)", sendOk, timedOut)
592                 xapp.Logger.Error("MSG-SubDelFail: %s", idstring(err, trans, subs))
593         }
594         return
595 }
596
597 //-------------------------------------------------------------------
598 //
599 //-------------------------------------------------------------------
600 func typeofSubsMessage(v interface{}) string {
601         if v == nil {
602                 return "NIL"
603         }
604         switch v.(type) {
605         case *e2ap.E2APSubscriptionRequest:
606                 return "SubReq"
607         case *e2ap.E2APSubscriptionResponse:
608                 return "SubResp"
609         case *e2ap.E2APSubscriptionFailure:
610                 return "SubFail"
611         case *e2ap.E2APSubscriptionDeleteRequest:
612                 return "SubDelReq"
613         case *e2ap.E2APSubscriptionDeleteResponse:
614                 return "SubDelResp"
615         case *e2ap.E2APSubscriptionDeleteFailure:
616                 return "SubDelFail"
617         default:
618                 return "Unknown"
619         }
620 }