Example #1
0
// messageAddAVPsWithPath will dynamically add AVPs into the message
// 	append:	append to the message, on false overwrite if AVP is single or add to group if AVP is Grouped
func messageSetAVPsWithPath(m *diam.Message, path []interface{}, avpValStr string, appnd bool, timezone string) error {
	if len(path) == 0 {
		return errors.New("Empty path as AVP filter")
	}
	dictAVPs := make([]*dict.AVP, len(path)) // for each subpath, one dictionary AVP
	for i, subpath := range path {
		if dictAVP, err := m.Dictionary().FindAVP(m.Header.ApplicationID, subpath); err != nil {
			return err
		} else if dictAVP == nil {
			return fmt.Errorf("Cannot find AVP with id: %s", path[len(path)-1])
		} else {
			dictAVPs[i] = dictAVP
		}
	}
	if dictAVPs[len(path)-1].Data.Type == diam.GroupedAVPType {
		return errors.New("Last AVP in path needs not to be GroupedAVP")
	}
	var msgAVP *diam.AVP // Keep a reference here towards last AVP
	lastAVPIdx := len(path) - 1
	for i := lastAVPIdx; i >= 0; i-- {
		var typeVal datatype.Type
		if i == lastAVPIdx {
			avpValByte, err := serializeAVPValueFromString(dictAVPs[i], avpValStr, timezone)
			if err != nil {
				return err
			}
			typeVal, err = datatype.Decode(dictAVPs[i].Data.Type, avpValByte)
			if err != nil {
				return err
			}
		} else {
			typeVal = &diam.GroupedAVP{
				AVP: []*diam.AVP{msgAVP}}
		}
		newMsgAVP := diam.NewAVP(dictAVPs[i].Code, avp.Mbit, dictAVPs[i].VendorID, typeVal) // FixMe: maybe Mbit with dictionary one
		if i == lastAVPIdx-1 && !appnd {                                                    // last AVP needs to be appended in group
			avps, _ := m.FindAVPsWithPath(path[:lastAVPIdx], dict.UndefinedVendorID)
			if len(avps) != 0 { // Group AVP already in the message
				prevGrpData := avps[0].Data.(*diam.GroupedAVP)
				prevGrpData.AVP = append(prevGrpData.AVP, msgAVP)
				m.Header.MessageLength += uint32(msgAVP.Len())
				return nil
			}
		}
		msgAVP = newMsgAVP
	}
	if !appnd { // Not group AVP, replace the previous set one with this one
		avps, _ := m.FindAVPsWithPath(path, dict.UndefinedVendorID)
		if len(avps) != 0 { // Group AVP already in the message
			m.Header.MessageLength -= uint32(avps[0].Len()) // decrease message length since we overwrite
			*avps[0] = *msgAVP
			m.Header.MessageLength += uint32(msgAVP.Len())
			return nil
		}
	}
	m.AVP = append(m.AVP, msgAVP)
	m.Header.MessageLength += uint32(msgAVP.Len())
	return nil
}
Example #2
0
// DecodeFromBytes decodes the bytes of a Diameter AVP.
// It uses the given application id and dictionary for decoding the bytes.
func (a *AVP) DecodeFromBytes(data []byte, application uint32, dictionary *dict.Parser) error {
	dl := len(data)
	if dl < 8 {
		return fmt.Errorf("Not enough data to decode AVP header: %d bytes", dl)
	}
	a.Code = binary.BigEndian.Uint32(data[0:4])
	a.Flags = data[4]
	a.Length = int(uint24to32(data[5:8]))
	if dl < int(a.Length) {
		return fmt.Errorf("Not enough data to decode AVP: %d != %d",
			dl, a.Length)
	}
	data = data[:a.Length] // this cuts padded bytes off
	var hdrLength int
	var payload []byte
	// Read VendorId when required.
	if a.Flags&avp.Vbit == avp.Vbit {
		a.VendorID = binary.BigEndian.Uint32(data[8:12])
		payload = data[12:]
		hdrLength = 12
	} else {
		payload = data[8:]
		hdrLength = 8
	}
	// Find this code in the dictionary.
	dictAVP, err := dictionary.FindAVPWithVendor(application, a.Code, a.VendorID)
	if err != nil {
		return err
	}
	bodyLen := a.Length - hdrLength
	if n := len(payload); n < bodyLen {
		return fmt.Errorf(
			"Not enough data to decode AVP: %d != %d",
			hdrLength, n,
		)
	}
	a.Data, err = datatype.Decode(dictAVP.Data.Type, payload)
	if err != nil {
		return err
	}
	// Handle grouped AVPs.
	if a.Data.Type() == datatype.GroupedType {
		a.Data, err = DecodeGrouped(
			a.Data.(datatype.Grouped),
			application, dictionary,
		)
		if err != nil {
			return err
		}
	}
	return nil
}