From b99312da48d43b87b57b37545cd75ec4074d1f4f Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 3 Jan 2019 15:50:25 +0100 Subject: [PATCH] DiameterAgent V1DisconnectSession implementation --- agents/diamagent.go | 45 +++++++++++++++++++++++++++++++++++++++++---- agents/libdiam.go | 40 ++++++++++++++++++++++++---------------- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/agents/diamagent.go b/agents/diamagent.go index 6e4ee1301..236efd096 100644 --- a/agents/diamagent.go +++ b/agents/diamagent.go @@ -165,13 +165,13 @@ func (da *DiameterAgent) handleMessage(c diam.Conn, m *diam.Message) { if da.cgrCfg.DiameterAgentCfg().ASRTempalte != "" { sessID, err := diamDP.FieldAsString([]string{"Session-Id"}) if err != nil { - utils.Logger.Err( + utils.Logger.Warning( fmt.Sprintf("<%s> failed retrieving Session-Id err: %s, message: %s", utils.DiameterAgent, err.Error(), m)) writeOnConn(c, diamErr) } // cache message data needed for building up the ASR - engine.Cache.Set(utils.CacheDiameterMessages, sessID, &diamMessageData{c, m, reqVars}, + engine.Cache.Set(utils.CacheDiameterMessages, sessID, &diamMsgData{c, m, reqVars}, nil, false, utils.NonTransactional) } // handle MaxActiveReqs @@ -376,8 +376,45 @@ func (da *DiameterAgent) Call(serviceMethod string, args interface{}, reply inte // V1DisconnectSession is part of the sessions.SessionSClient func (da *DiameterAgent) V1DisconnectSession(args utils.AttrDisconnectSession, reply *string) (err error) { - //m := NewMessage(cmd uint32, 0, appid, 0, 0, m.Dictionary()) - return utils.ErrNotImplemented + ssID, has := args.EventStart[utils.OriginID] + if !has { + utils.Logger.Info( + fmt.Sprintf("<%s> cannot disconnect session, missing OriginID in event: %s", + utils.DiameterAgent, utils.ToJSON(args.EventStart))) + return utils.ErrMandatoryIeMissing + } + msg, has := engine.Cache.Get(utils.CacheDiameterMessages, ssID.(string)) + if !has { + utils.Logger.Warning( + fmt.Sprintf("<%s> cannot retrieve message from cache with OriginID: <%s>", + utils.DiameterAgent, ssID)) + return utils.ErrMandatoryIeMissing + } + dmd := msg.(*diamMsgData) + aReq := newAgentRequest( + newDADataProvider(dmd.c, dmd.m), + dmd.vars, nil, nil, + da.cgrCfg.GeneralCfg().DefaultTenant, + da.cgrCfg.GeneralCfg().DefaultTimezone, da.filterS) + nM, err := aReq.AsNavigableMap(da.cgrCfg.DiameterAgentCfg().Templates[da.cgrCfg.DiameterAgentCfg().ASRTempalte]) + if err != nil { + utils.Logger.Warning( + fmt.Sprintf("<%s> cannot disconnect session with OriginID: <%s>, err: %s", + utils.DiameterAgent, ssID, err.Error())) + return utils.ErrServerError + } + m := diam.NewMessage(dmd.m.Header.CommandCode, 0, dmd.m.Header.ApplicationID, 0, 0, dmd.m.Dictionary()) + if err = updateDiamMsgFromNavMap(m, nM, da.cgrCfg.GeneralCfg().DefaultTimezone); err != nil { + utils.Logger.Warning( + fmt.Sprintf("<%s> cannot disconnect session with OriginID: <%s>, err: %s", + utils.DiameterAgent, ssID, err.Error())) + return utils.ErrServerError + } + if err = writeOnConn(dmd.c, m); err != nil { + return utils.ErrServerError + } + *reply = utils.OK + return } // V1GetActiveSessionIDs is part of the sessions.SessionSClient diff --git a/agents/libdiam.go b/agents/libdiam.go index e19e7eae7..09609c0a9 100644 --- a/agents/libdiam.go +++ b/agents/libdiam.go @@ -266,11 +266,12 @@ func messageSetAVPsWithPath(m *diam.Message, pathStr []string, } // writeOnConn writes the message on connection, logs failures -func writeOnConn(c diam.Conn, m *diam.Message) { - if _, err := m.WriteTo(c); err != nil { +func writeOnConn(c diam.Conn, m *diam.Message) (err error) { + if _, err = m.WriteTo(c); err != nil { utils.Logger.Warning(fmt.Sprintf("<%s> failed writing message to %s, err: %s, msg: %s", utils.DiameterAgent, c.RemoteAddr(), err.Error(), m)) } + return } // newDADataProvider constructs a DataProvider for a diameter message @@ -404,20 +405,14 @@ func (dP *diameterDP) FieldAsInterface(fldPath []string) (data interface{}, err return } -// diamAnswer builds up the answer to be sent back to the client -func diamAnswer(m *diam.Message, resCode uint32, errFlag bool, - rply *config.NavigableMap, tmz string) (a *diam.Message, err error) { - a = newDiamAnswer(m, resCode) - if errFlag { - a.Header.CommandFlags = diam.ErrorFlag - } +// updateDiamMsgFromNavMap will update the diameter message with items from navigable map +func updateDiamMsgFromNavMap(m *diam.Message, navMp *config.NavigableMap, tmz string) (err error) { // write reply into message pathIdx := make(map[string]int) // group items for same path - for _, val := range rply.Values() { - + for _, val := range navMp.Values() { nmItms, isNMItems := val.([]*config.NMItem) if !isNMItems { - return nil, fmt.Errorf("cannot encode reply value: %s, err: not NMItems", utils.ToJSON(val)) + return fmt.Errorf("cannot encode reply value: %s, err: not NMItems", utils.ToJSON(val)) } // find out the first itm which is not an attribute var itm *config.NMItem @@ -441,20 +436,33 @@ func diamAnswer(m *diam.Message, resCode uint32, errFlag bool, } itmStr, err := utils.IfaceAsString(itm.Data) if err != nil { - return nil, fmt.Errorf("cannot convert data: %+v to string, err: %s", itm.Data, err) + return fmt.Errorf("cannot convert data: %+v to string, err: %s", itm.Data, err) } var newBranch bool if itm.Config != nil && itm.Config.NewBranch { newBranch = true } - if err = messageSetAVPsWithPath(a, itm.Path, + if err = messageSetAVPsWithPath(m, itm.Path, itmStr, newBranch, tmz); err != nil { - return nil, fmt.Errorf("setting item with path: %+v got err: %s", itm.Path, err.Error()) + return fmt.Errorf("setting item with path: %+v got err: %s", itm.Path, err.Error()) } } return } +// diamAnswer builds up the answer to be sent back to the client +func diamAnswer(m *diam.Message, resCode uint32, errFlag bool, + rply *config.NavigableMap, tmz string) (a *diam.Message, err error) { + a = newDiamAnswer(m, resCode) + if errFlag { + a.Header.CommandFlags = diam.ErrorFlag + } + if err = updateDiamMsgFromNavMap(a, rply, tmz); err != nil { + return nil, err + } + return +} + // negDiamAnswer is used to return the negative answer we need previous to func diamErr(m *diam.Message, resCode uint32, reqVars map[string]interface{}, @@ -507,7 +515,7 @@ func newDiamAnswer(m *diam.Message, resCode uint32) *diam.Message { } // diamMessageData is cached when data is needed (ie. ) -type diamMessageData struct { +type diamMsgData struct { c diam.Conn m *diam.Message vars map[string]interface{}