首页 > 解决方案 > 如何执行动态解组

问题描述

任何人都可以根据从直径客户端收到的消息类型帮助我执行动态解组。在下面的代码中,我必须使用两个结构来表示直径服务器接收到的两条不同消息。我想修改将请求解组到结构的当前代码,以便根据接收到的与特定结构匹配的消息,var req HandleDERRequest动态地对var req HandleDERRequest或进行解组。var challreq HandleChallRequest我试图用下面的代码来实现,但它不能正常工作。所有答案都同时返回,这不是我所期望的。

func HandleDER(settings sm.Settings) diam.HandlerFunc {

    // If received AVP messages are of this struct format, Unmarshal message to this structure

    type HandleDERRequest struct {
        SessionID         datatype.UTF8String       `avp:"Session-Id"`
        OriginHost        datatype.DiameterIdentity `avp:"Origin-Host"`
        OriginRealm       datatype.DiameterIdentity `avp:"Origin-Realm"`
        DestinationHost   datatype.DiameterIdentity `avp:"Destination-Host"`
        DestinationRealm  datatype.DiameterIdentity `avp:"Destination-Realm"`
        UserName          datatype.UTF8String       `avp:"User-Name"`
        AuthSessionState  datatype.Enumerated       `avp:"Auth-Session-State"`
        AuthApplicationID datatype.Unsigned32       `avp:"Auth-Application-Id"`
        AuthRequestType   datatype.Enumerated       `avp:"Auth-Request-Type"`
        EAPPayload        datatype.OctetString      `avp:"EAP-Payload"`
        RATType           datatype.Enumerated       `avp:"RAT-Type"`
        ANID              datatype.UTF8String       `avp:"ANID"`
    }

    // If received AVP messages are of this struct format, Unmarshal message to this structure

    type HandleChallRequest struct {
        SessionID        datatype.UTF8String       `avp:"Session-Id"`
        OriginHost       datatype.DiameterIdentity `avp:"Origin-Host"`
        OriginRealm      datatype.DiameterIdentity `avp:"Origin-Realm"`
        DestinationHost  datatype.DiameterIdentity `avp:"Destination-Host"`
        DestinationRealm datatype.DiameterIdentity `avp:"Destination-Realm"`
        EAPPayload       datatype.OctetString      `avp:"EAP-Payload"`
    }

    return func(c diam.Conn, m *diam.Message) {

        var err error = nil
        var req HandleDERRequest

        var code uint32 = diam.Success
        err = m.Unmarshal(&req)
        if err != nil {
            err = fmt.Errorf("Unmarshal failed: %s", err)
            code = diam.UnableToComply
            log.Printf("Invalid DER(%d): %s\n", code, err.Error())
        }
        a := m.Answer(code)
        a.NewAVP(avp.SessionID, avp.Mbit, 0, req.SessionID)
        a.NewAVP(avp.OriginHost, avp.Mbit, 0, req.DestinationHost)
        a.NewAVP(avp.OriginRealm, avp.Mbit, 0, req.DestinationRealm)
        a.NewAVP(avp.OriginStateID, avp.Mbit, 0, settings.OriginStateID)
        _, err = AKA_Challenge_Request(settings, c, a)
        if err != nil {
            log.Printf("Failed to send AAA challenge request: %s", err.Error())
        }

        var challreq HandleChallageRequest
        err = m.Unmarshal(&challreq)
        if err != nil {
            err = fmt.Errorf("Unmarshal failed: %s", err)
            code = diam.UnableToComply
            log.Printf("Invalid DER(%d): %s\n", code, err.Error())
        }
        a = m.Answer(code)
        a.NewAVP(avp.SessionID, avp.Mbit, 0, req.SessionID)
        a.NewAVP(avp.OriginHost, avp.Mbit, 0, req.DestinationHost)
        a.NewAVP(avp.OriginRealm, avp.Mbit, 0, req.DestinationRealm)
        a.NewAVP(avp.OriginStateID, avp.Mbit, 0, settings.OriginStateID)
        _, err = AKA_Success_Notification(settings, c, a)
        if err != nil {
           log.Printf("Failed to send Success Notification: %s", err.Error())
       }
    }
}
func AKA_Challenge_Request(settings sm.Settings, w io.Writer, m *diam.Message) (n int64, err error) {
    PayloadSlice := []byte(`RAND, AUTHN, MAC, RESULT_ID`)
    m.NewAVP(avp.EAPPayload, avp.Mbit, 0, datatype.OctetString(PayloadSlice))
    return m.WriteTo(w)
}

func AKA_Success_Notification(settings sm.Settings, w io.Writer, m *diam.Message) (n int64, err error) {
    EAPSlice := []byte(`EAP_Success`)
    MSKSlice := []byte(`EAP-Master-Session-Key`)
    m.NewAVP(avp.EAPPayload, avp.Mbit, 0, datatype.OctetString(EAPSlice))
    m.NewAVP(avp.EAPMasterSessionKey, avp.Mbit, 0, datatype.OctetString(MSKSlice))
    return m.WriteTo(w)
}

我知道返回函数应该有一个 if 条件,但我不知道如何开始。请任何关于如何去做的想法。

标签: gounmarshalling

解决方案


我想说此时不需要 HandleChallRequest 类型。如果我正确读取了字段,这两种类型都具有相同的基本属性,但 HandleDERRequest 类型具有更多属性,那么这些不仅仅是未编组类型中的 nil 值吗?

然后,您可以进行某种 nil 检查以确定一个数据集与另一个数据集,或者更优选的是创建一个包含所有字段和一组通用方法的接口,以便您可以创建两种类型来实现此接口选择变成了创建哪一个。

编辑 1。

再次抱歉,如果我没有抓住重点,但我仍然认为不需要不同的类型,在我看来它们只是数据容器,具有不同的数据。

这是我在单一数据类型方面的想法。

func HandleDER(settings sm.Settings) diam.HandlerFunc {

// If received AVP messages are of this struct format, Unmarshal message to this structure

type HandleRequest struct {
    SessionID         datatype.UTF8String       `avp:"Session-Id"`
    OriginHost        datatype.DiameterIdentity `avp:"Origin-Host"`
    OriginRealm       datatype.DiameterIdentity `avp:"Origin-Realm"`
    DestinationHost   datatype.DiameterIdentity `avp:"Destination-Host"`
    DestinationRealm  datatype.DiameterIdentity `avp:"Destination-Realm"`
    UserName          datatype.UTF8String       `avp:"User-Name"`
    AuthSessionState  datatype.Enumerated       `avp:"Auth-Session-State"`
    AuthApplicationID datatype.Unsigned32       `avp:"Auth-Application-Id"`
    AuthRequestType   datatype.Enumerated       `avp:"Auth-Request-Type"`
    EAPPayload        datatype.OctetString      `avp:"EAP-Payload"`
    RATType           datatype.Enumerated       `avp:"RAT-Type"`
    ANID              datatype.UTF8String       `avp:"ANID"`
}

// If received AVP messages are of this struct format, Unmarshal message to this structure

return func(c diam.Conn, m *diam.Message) {

    var err error = nil
    var req HandleRequest

    var code uint32 = diam.Success

    err = m.Unmarshal(&req)
    if err != nil {
        err = fmt.Errorf("Unmarshal failed: %s", err)
        code = diam.UnableToComply
        log.Printf("Invalid DER(%d): %s\n", code, err.Error())
    }
    a := m.Answer(code)
    a.NewAVP(avp.SessionID, avp.Mbit, 0, req.SessionID)
    a.NewAVP(avp.OriginHost, avp.Mbit, 0, req.DestinationHost)
    a.NewAVP(avp.OriginRealm, avp.Mbit, 0, req.DestinationRealm)
    a.NewAVP(avp.OriginStateID, avp.Mbit, 0, settings.OriginStateID)

    if ("messagetype" == "first message type") {
        _, err = AKA_Challenge_Request(settings, c, a)
        if err != nil {
            log.Printf("Failed to send AAA challenge request: %s", err.Error())
        }
    } else {
        _, err = AKA_Success_Notification(settings, c, a)
        if err != nil {
            log.Printf("Failed to send Success Notification: %s", err.Error())
        }
    }
}

}


推荐阅读