130 lines
3 KiB
Go
130 lines
3 KiB
Go
|
package radius // import "layeh.com/radius"
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// Builtin is the built-in dictionary. It is initially loaded with the
|
||
|
// attributes defined in RFC 2865 and RFC 2866.
|
||
|
var Builtin *Dictionary
|
||
|
|
||
|
type dictEntry struct {
|
||
|
Type byte
|
||
|
Name string
|
||
|
Codec AttributeCodec
|
||
|
}
|
||
|
|
||
|
// Dictionary stores mappings between attribute names and types and
|
||
|
// AttributeCodecs.
|
||
|
type Dictionary struct {
|
||
|
mu sync.RWMutex
|
||
|
attributesByType [256]*dictEntry
|
||
|
attributesByName map[string]*dictEntry
|
||
|
}
|
||
|
|
||
|
// Register registers the AttributeCodec for the given attribute name and type.
|
||
|
func (d *Dictionary) Register(name string, t byte, codec AttributeCodec) error {
|
||
|
d.mu.Lock()
|
||
|
if d.attributesByType[t] != nil {
|
||
|
d.mu.Unlock()
|
||
|
return errors.New("radius: attribute already registered")
|
||
|
}
|
||
|
entry := &dictEntry{
|
||
|
Type: t,
|
||
|
Name: name,
|
||
|
Codec: codec,
|
||
|
}
|
||
|
d.attributesByType[t] = entry
|
||
|
if d.attributesByName == nil {
|
||
|
d.attributesByName = make(map[string]*dictEntry)
|
||
|
}
|
||
|
d.attributesByName[name] = entry
|
||
|
d.mu.Unlock()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// MustRegister is a helper for Register that panics if it returns an error.
|
||
|
func (d *Dictionary) MustRegister(name string, t byte, codec AttributeCodec) {
|
||
|
if err := d.Register(name, t, codec); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (d *Dictionary) get(name string) (t byte, codec AttributeCodec, ok bool) {
|
||
|
d.mu.RLock()
|
||
|
entry := d.attributesByName[name]
|
||
|
d.mu.RUnlock()
|
||
|
if entry == nil {
|
||
|
return
|
||
|
}
|
||
|
t = entry.Type
|
||
|
codec = entry.Codec
|
||
|
ok = true
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Attr returns a new *Attribute whose type is registered under the given
|
||
|
// name.
|
||
|
//
|
||
|
// If name is not registered, nil and an error is returned.
|
||
|
func (d *Dictionary) Attr(name string, value interface{}) (*Attribute, error) {
|
||
|
t, _, ok := d.get(name)
|
||
|
if !ok {
|
||
|
return nil, errors.New("radius: attribute name not registered")
|
||
|
}
|
||
|
return &Attribute{
|
||
|
Type: t,
|
||
|
Value: value,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// MustAttr is a helper for Attr that panics if Attr were to return an error.
|
||
|
func (d *Dictionary) MustAttr(name string, value interface{}) *Attribute {
|
||
|
attr, err := d.Attr(name, value)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
return attr
|
||
|
}
|
||
|
|
||
|
// Name returns the registered name for the given attribute type. ok is false
|
||
|
// if the given type is not registered.
|
||
|
func (d *Dictionary) Name(t byte) (name string, ok bool) {
|
||
|
d.mu.RLock()
|
||
|
entry := d.attributesByType[t]
|
||
|
d.mu.RUnlock()
|
||
|
if entry == nil {
|
||
|
return
|
||
|
}
|
||
|
name = entry.Name
|
||
|
ok = true
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Type returns the registered type for the given attribute name. ok is false
|
||
|
// if the given name is not registered.
|
||
|
func (d *Dictionary) Type(name string) (t byte, ok bool) {
|
||
|
d.mu.RLock()
|
||
|
entry := d.attributesByName[name]
|
||
|
d.mu.RUnlock()
|
||
|
if entry == nil {
|
||
|
return
|
||
|
}
|
||
|
t = entry.Type
|
||
|
ok = true
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Codec returns the AttributeCodec for the given registered type. nil is
|
||
|
// returned if the given type is not registered.
|
||
|
func (d *Dictionary) Codec(t byte) AttributeCodec {
|
||
|
d.mu.RLock()
|
||
|
entry := d.attributesByType[t]
|
||
|
d.mu.RUnlock()
|
||
|
if entry == nil {
|
||
|
return AttributeUnknown
|
||
|
}
|
||
|
return entry.Codec
|
||
|
}
|