Files
stun/attribute_fingerprint.go
2017-02-11 05:23:49 +03:00

69 lines
1.7 KiB
Go

package stun
import (
"fmt"
"hash/crc32"
)
// FingerprintAttr represent FINGERPRINT attribute.
type FingerprintAttr struct{}
// CRCMismatch represents CRC check error.
type CRCMismatch struct {
Expected uint32
Actual uint32
}
func (m CRCMismatch) Error() string {
return fmt.Sprintf("CRC mismatch: %x (expected) != %x (actual)",
m.Expected,
m.Actual,
)
}
// Fingerprint is shorthand for FingerprintAttr.
var Fingerprint = &FingerprintAttr{}
const (
fingerprintXORValue uint32 = 0x5354554e
fingerprintSize = 4 // 32 bit
)
// FingerprintValue returns CRC32 of m XOR-ed by 0x5354554e.
func FingerprintValue(b []byte) uint32 {
return crc32.ChecksumIEEE(b) ^ fingerprintXORValue // XOR
}
// AddTo adds fingerprint to message.
func (FingerprintAttr) AddTo(m *Message) error {
l := m.Length
// length in header should include size of fingerprint attribute
m.Length += fingerprintSize + attributeHeaderSize // increasing length
m.WriteLength() // writing Length to Raw
b := make([]byte, fingerprintSize)
v := FingerprintValue(m.Raw)
bin.PutUint32(b, v)
m.Length = l
m.Add(AttrFingerprint, b)
return nil
}
// Check reads fingerprint value from m and checks it, returning error if any.
// Can return *DecodeErr, ErrAttributeNotFound and *CRCMismatch.
func (FingerprintAttr) Check(m *Message) error {
v, err := m.Get(AttrFingerprint)
if err != nil {
return err
}
if len(v) != fingerprintSize {
return newDecodeErr("message", "fingerprint", "bad length")
}
val := bin.Uint32(v)
attrStart := len(m.Raw) - (fingerprintSize + attributeHeaderSize)
expected := FingerprintValue(m.Raw[:attrStart])
if expected != val {
return &CRCMismatch{Expected: expected, Actual: val}
}
return nil
}