diam

package
v3.0.2+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 20, 2018 License: BSD-3-Clause Imports: 20 Imported by: 318

Documentation

Overview

Package diam provides support for the Diameter Base Protocol for Go. See RFC 6733 for details.

go-diameter is minimalist implementation of the Diameter Base Protocol, organized in sub-packages with specific functionality:

  • diam: the main package, provides the capability of encoding and decoding messages, and a client and server API similar to net/http.

  • diam/diamtest: Server test API analogous to net/http/httptest.

  • diam/avp: Diameter attribute-value-pairs codes and flags.

  • diam/datatype: AVP data types (e.g. Unsigned32, OctetString).

  • diam/dict: a dictionary parser that supports collections of dictionaries.

If you're looking to go right into code, see the examples subdirectory for applications like clients and servers.

Diameter Applications

All diameter applications require at least the following:

  • A dictionary with the application id, its commands and message formats
  • A program that implements the application, driven by the dictionary

The diam/dict sub-package supports the base application (id 0, RFC 6733) and the credit control application (id 4, RFC 4006). Each application has its own commands and messages, and their pre-defined AVPs.

AVP data have specific data types, like UTF8String, Unsigned32 and so on. Fortunately, those data types map well with Go types, which makes things easier for us. However, the AVP data types have specific properties like padding for certain strings, which have to be taken care of. The sub-package diam/datatype handles it all.

At last, the diam package is used to build clients and servers using an API very similar to the one of net/http. To initiate the client or server, you'll have to pass a dictionary. Messages sent and received are encoded and decoded using the dictionary automatically.

The API of clients and servers require that you assign handlers for certain messages, similar to how you route HTTP endpoints. In the handlers, you'll receive messages already decoded.

Index

Constants

View Source
const (
	BASE_APP_ID             = 0
	NETWORK_ACCESS_APP_ID   = 1
	BASE_ACCOUNTING_APP_ID  = 3
	CHARGING_CONTROL_APP_ID = 4
	TGPP_APP_ID             = 4
	TGPP_S6A_APP_ID         = 16777251
)

Diameter application IDs.

View Source
const (
	MultiRoundAuth         = 1001
	Success                = 2001
	LimitedSuccess         = 2002
	CommandUnsupported     = 3001
	UnableToDeliver        = 3002
	RealmNotServed         = 3003
	TooBusy                = 3004
	LoopDetected           = 3005
	RedirectIndication     = 3006
	ApplicationUnsupported = 3007
	InvalidHDRBits         = 3008
	InvalidAVPBits         = 3009
	UnknownPeer            = 3010
	AuthenticationRejected = 4001
	OutOfSpace             = 4002
	ElectionLost           = 4003
	AVPUnsupported         = 5001
	UnknownSessionID       = 5002
	AuthorizationRejected  = 5003
	InvalidAVPValue        = 5004
	MissingAVP             = 5005
	ResourcesExceeded      = 5006
	ContradictingAVPs      = 5007
	AVPNotAllowed          = 5008
	AVPOccursTooManyTimes  = 5009
	NoCommonApplication    = 5010
	UnsupportedVersion     = 5011
	UnableToComply         = 5012
	InvalidBitInHeader     = 5013
	InvalidAVPLenght       = 5014
	InvalidMessageLength   = 5015
	InvalidAVPBitCombo     = 5016
	NoCommonSecurity       = 5017
)

Diameter codes for the Result-Code AVP.

View Source
const (
	AA                        = 265
	AbortSession              = 274
	Accounting                = 271
	AuthenticationInformation = 318
	CancelLocation            = 317
	CapabilitiesExchange      = 257
	CreditControl             = 272
	DeviceWatchdog            = 280
	DisconnectPeer            = 282
	Notify                    = 323
	PurgeUE                   = 321
	ReAuth                    = 258
	SessionTermination        = 275
	UpdateLocation            = 316
)

Diameter command codes.

View Source
const (
	AAA = "AAA"
	AAR = "AAR"
	ACA = "ACA"
	ACR = "ACR"
	AIA = "AIA"
	AIR = "AIR"
	ASA = "ASA"
	ASR = "ASR"
	CCA = "CCA"
	CCR = "CCR"
	CEA = "CEA"
	CER = "CER"
	CLA = "CLA"
	CLR = "CLR"
	DPA = "DPA"
	DPR = "DPR"
	DWA = "DWA"
	DWR = "DWR"
	NOA = "NOA"
	NOR = "NOR"
	PUA = "PUA"
	PUR = "PUR"
	RAA = "RAA"
	RAR = "RAR"
	STA = "STA"
	STR = "STR"
	ULA = "ULA"
	ULR = "ULR"
)

Short Command Names

View Source
const (
	RequestFlag       = 1 << 7
	ProxiableFlag     = 1 << 6
	ErrorFlag         = 1 << 5
	RetransmittedFlag = 1 << 4
)

Command flags.

View Source
const GroupedAVPType = 50

GroupedAVPType is the identifier of the GroupedAVP data type. It must not conflict with other values from the datatype package.

View Source
const HeaderLength = 20

HeaderLength is the length of a Diameter header data structure.

Variables

View Source
var ALL_CMD_INDEX = CommandIndex{^uint32(0), ^uint32(0), false}
View Source
var DefaultServeMux = NewServeMux()

DefaultServeMux is the default ServeMux used by Serve.

View Source
var MessageBufferLength = 1 << 10

MessageBufferLength is the default buffer length for Diameter messages.

Functions

func ErrorReports

func ErrorReports() <-chan *ErrorReport

ErrorReports returns the ErrorReport channel of the DefaultServeMux.

func Handle

func Handle(cmd string, handler Handler)

Handle registers the handler object for the given command in the DefaultServeMux.

func HandleFunc

func HandleFunc(cmd string, handler func(Conn, *Message))

HandleFunc registers the handler function for the given command in the DefaultServeMux.

func Listen

func Listen(network, address string) (net.Listener, error)

func ListenAndServe

func ListenAndServe(addr string, handler Handler, dp *dict.Parser) error

ListenAndServe listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections.

If handler is nil, DefaultServeMux is used.

If dict is nil, dict.Default is used.

func ListenAndServeNetwork

func ListenAndServeNetwork(network, addr string, handler Handler, dp *dict.Parser) error

ListenAndServeNetwork listens on the network & addr and then calls Serve with handler to handle requests on incoming connections.

If handler is nil, DefaultServeMux is used.

If dict is nil, dict.Default is used.

func ListenAndServeNetworkTLS

func ListenAndServeNetworkTLS(network, addr string, certFile string, keyFile string, handler Handler, dp *dict.Parser) error

ListenAndServeNetworkTLS acts identically to ListenAndServeNetwork, except that it expects SSL connections. Additionally, files containing a certificate and matching private key for the server must be provided. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate followed by the CA's certificate.

One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.

func ListenAndServeTLS

func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler, dp *dict.Parser) error

ListenAndServeTLS acts identically to ListenAndServe, except that it expects SSL connections. Additionally, files containing a certificate and matching private key for the server must be provided. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate followed by the CA's certificate.

One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.

func Serve

func Serve(l net.Listener, handler Handler) error

Serve accepts incoming diameter connections on the listener l, creating a new service goroutine for each. The service goroutines read messages and then call handler to reply to them. Handler is typically nil, in which case the DefaultServeMux is used.

func TLSConfigClone

func TLSConfigClone(cfg *tls.Config) *tls.Config

Types

type AVP

type AVP struct {
	Code     uint32        // Code of this AVP
	Flags    uint8         // Flags of this AVP
	Length   int           // Length of this AVP's payload
	VendorID uint32        // VendorId of this AVP
	Data     datatype.Type // Data of this AVP (payload)
}

AVP is a Diameter attribute-value-pair.

func DecodeAVP

func DecodeAVP(data []byte, application uint32, dictionary *dict.Parser) (*AVP, error)

DecodeAVP decodes the bytes of a Diameter AVP. It uses the given application id and dictionary for decoding the bytes.

func NewAVP

func NewAVP(code uint32, flags uint8, vendor uint32, data datatype.Type) *AVP

NewAVP creates and initializes a new AVP.

func (*AVP) DecodeFromBytes

func (a *AVP) DecodeFromBytes(data []byte, application uint32, dictionary *dict.Parser) error

DecodeFromBytes decodes the bytes of a Diameter AVP. It uses the given application id and dictionary for decoding the bytes.

func (*AVP) Len

func (a *AVP) Len() int

Len returns the length of this AVP in bytes with padding.

func (*AVP) Serialize

func (a *AVP) Serialize() ([]byte, error)

Serialize returns the byte sequence that represents this AVP. It requires at least the Code, Flags and Data fields set.

func (*AVP) SerializeTo

func (a *AVP) SerializeTo(b []byte) error

SerializeTo writes the byte sequence that represents this AVP to a byte array.

func (*AVP) String

func (a *AVP) String() string

type CloseNotifier

type CloseNotifier interface {
	// CloseNotify returns a channel that is closed
	// when the client connection has gone away.
	CloseNotify() <-chan struct{}
}

The CloseNotifier interface is implemented by Conns which allow detecting when the underlying connection has gone away.

This mechanism can be used to detect if a peer has disconnected.

type CommandIndex

type CommandIndex struct {
	AppID   uint32
	Code    uint32
	Request bool
}

type Conn

type Conn interface {
	Write(b []byte) (int, error)    // Writes a msg to the connection
	Close()                         // Close the connection
	LocalAddr() net.Addr            // Returns the local IP
	RemoteAddr() net.Addr           // Returns the remote IP
	TLS() *tls.ConnectionState      // TLS or nil when not using TLS
	Dictionary() *dict.Parser       // Dictionary parser of the connection
	Context() context.Context       // Returns the internal context
	SetContext(ctx context.Context) // Stores a new context
	Connection() net.Conn           // Returns network connection

}

Conn interface is used by a handler to send diameter messages.

func Dial

func Dial(addr string, handler Handler, dp *dict.Parser) (Conn, error)

Dial connects to the peer pointed to by addr and returns the Conn that can be used to send diameter messages. Incoming messages are handled by the handler, which is typically nil and DefaultServeMux is used. If dict is nil, dict.Default is used.

func DialNetwork

func DialNetwork(network, addr string, handler Handler, dp *dict.Parser) (Conn, error)

DialNetwork connects to the peer pointed to by network & addr and returns the Conn that can be used to send diameter messages. Incoming messages are handled by the handler, which is typically nil and DefaultServeMux is used. If dict is nil, dict.Default is used.

func DialNetworkTLS

func DialNetworkTLS(network, addr, certFile, keyFile string, handler Handler, dp *dict.Parser) (Conn, error)

DialNetworkTLS is the same as DialNetwork, but for TLS.

func DialNetworkTimeout

func DialNetworkTimeout(network, addr string, handler Handler, dp *dict.Parser, timeout time.Duration) (Conn, error)

func DialTLS

func DialTLS(addr, certFile, keyFile string, handler Handler, dp *dict.Parser) (Conn, error)

DialTLS is the same as Dial, but for TLS.

func DialTLSTimeout

func DialTLSTimeout(addr, certFile, keyFile string, handler Handler, dp *dict.Parser, timeout time.Duration) (Conn, error)

DialTLSTimeout is the same as DialTimeout, but for TLS.

func DialTimeout

func DialTimeout(addr string, handler Handler, dp *dict.Parser, timeout time.Duration) (Conn, error)

func NewConn

func NewConn(rw net.Conn, addr string, handler Handler, dp *dict.Parser) (Conn, error)

NewConn is the same as Dial, but using an already open net.Conn.

type Dialer

type Dialer interface {
	Dial(network, address string) (net.Conn, error)
}

type ErrorReport

type ErrorReport struct {
	Conn    Conn     // Peer that caused the error
	Message *Message // Message that caused the error
	Error   error    // Error message
}

ErrorReport is sent out of the server in case it fails to read messages due to a bad dictionary or network errors.

func (*ErrorReport) String

func (er *ErrorReport) String() string

String returns an error message. It does not render the Message field.

type ErrorReporter

type ErrorReporter interface {
	// Error writes an error to the reporter.
	Error(err *ErrorReport)

	// ErrorReports returns a channel that receives
	// errors from the connection.
	ErrorReports() <-chan *ErrorReport
}

The ErrorReporter interface is implemented by Handlers that allow reading errors from the underlying connection, like parsing diameter messages or connection errors.

type GroupedAVP

type GroupedAVP struct {
	AVP []*AVP
}

GroupedAVP that is different from the dummy datatype.Grouped.

func DecodeGrouped

func DecodeGrouped(data datatype.Grouped, application uint32, dictionary *dict.Parser) (*GroupedAVP, error)

DecodeGrouped decodes a Grouped AVP from a datatype.Grouped (byte array).

func (*GroupedAVP) AddAVP

func (g *GroupedAVP) AddAVP(a *AVP)

AddAVP adds the AVP to the GroupedAVP. It is not safe for concurrent calls.

func (*GroupedAVP) Len

func (g *GroupedAVP) Len() int

Len implements the datatype.Type interface.

func (*GroupedAVP) Padding

func (g *GroupedAVP) Padding() int

Padding implements the datatype.Type interface.

func (*GroupedAVP) Serialize

func (g *GroupedAVP) Serialize() []byte

Serialize implements the datatype.Type interface.

func (*GroupedAVP) String

func (g *GroupedAVP) String() string

String implements the datatype.Type interface.

func (*GroupedAVP) Type

func (g *GroupedAVP) Type() datatype.TypeID

Type implements the datatype.Type interface.

type Handler

type Handler interface {
	// ServeDIAM should write messages to the Conn and then return.
	// Returning signals that the request is finished and that the
	// server can move on to the next request on the connection.
	ServeDIAM(Conn, *Message)
}

The Handler interface allow arbitrary objects to be registered to serve particular messages like CER, DWR.

type HandlerFunc

type HandlerFunc func(Conn, *Message)

The HandlerFunc type is an adapter to allow the use of ordinary functions as diameter handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.

func (HandlerFunc) ServeDIAM

func (f HandlerFunc) ServeDIAM(c Conn, m *Message)

ServeDIAM calls f(c, m).

type Header struct {
	Version       uint8
	MessageLength uint32
	CommandFlags  uint8
	CommandCode   uint32
	ApplicationID uint32
	HopByHopID    uint32
	EndToEndID    uint32
}

Header is the header representation of a Diameter message.

func DecodeHeader

func DecodeHeader(data []byte) (*Header, error)

DecodeHeader decodes the bytes of a Diameter Header.

func (*Header) DecodeFromBytes

func (h *Header) DecodeFromBytes(data []byte) error

DecodeFromBytes decodes the bytes of a Diameter Header.

func (*Header) Serialize

func (h *Header) Serialize() []byte

Serialize returns a byte sequence of the header in network byte order.

func (*Header) SerializeTo

func (h *Header) SerializeTo(b []byte)

SerializeTo serializes the header to a byte sequence in network byte order.

func (*Header) String

func (h *Header) String() string

type Message

type Message struct {
	Header *Header
	AVP    []*AVP // AVPs in this message.
	// contains filtered or unexported fields
}

Message represents a Diameter message.

func NewMessage

func NewMessage(cmd uint32, flags uint8, appid, hopbyhop, endtoend uint32, dictionary *dict.Parser) *Message

NewMessage creates and initializes a Message.

func NewRequest

func NewRequest(cmd uint32, appid uint32, dictionary *dict.Parser) *Message

NewRequest creates a new Message with the Request bit set.

func ReadMessage

func ReadMessage(reader io.Reader, dictionary *dict.Parser) (*Message, error)

ReadMessage reads a binary stream from the reader and uses the given dictionary to parse it.

func (*Message) AddAVP

func (m *Message) AddAVP(a *AVP)

AddAVP adds the AVP to the Message. It is not safe for concurrent calls.

func (*Message) Answer

func (m *Message) Answer(resultCode uint32) *Message

Answer creates an answer for the current Message with an embedded Result-Code AVP.

func (*Message) Dictionary

func (m *Message) Dictionary() *dict.Parser

Dictionary returns the dictionary parser object associated with this message. This dictionary is used to encode and decode the message. If no dictionary is associated then it returns the default dictionary.

func (*Message) FindAVP

func (m *Message) FindAVP(code interface{}, vendorID uint32) (*AVP, error)

FindAVP searches the Message for a specific AVP. The code can be either the AVP code (int, uint32) or name (string).

Example:

avp, err := m.FindAVP(264)
avp, err := m.FindAVP(avp.OriginHost)
avp, err := m.FindAVP("Origin-Host")

func (*Message) FindAVPs

func (m *Message) FindAVPs(code interface{}, vendorID uint32) ([]*AVP, error)

FindAVPs searches the Message for all avps that match the search criteria. The code can be either the AVP code (int, uint32) or name (string).

Example:

avps, err := m.FindAVPs(264)
avps, err := m.FindAVPs(avp.OriginHost)
avps, err := m.FindAVPs("Origin-Host")

func (*Message) FindAVPsWithPath

func (m *Message) FindAVPsWithPath(path []interface{}, vendorID uint32) ([]*AVP, error)

FindAVPsWithPath searches the Message for AVPs on specific path. Used for example on group hierarchies. The path elements can be either AVP code (int, uint32), name (string) or combination of them.

Example:

avp, err := m.FindAVPsWithPath([]interface{}{264})
avp, err := m.FindAVPsWithPath([]interface{}{avp.OriginHost})
avp, err := m.FindAVPsWithPath([]interface{}{"Origin-Host"})

func (*Message) InsertAVP

func (m *Message) InsertAVP(a *AVP)

InsertAVP inserts the AVP to the Message as the first AVP. It is not safe for concurrent calls.

func (*Message) Len

func (m *Message) Len() int

Len returns the length of the Message in bytes.

func (*Message) Marshal

func (m *Message) Marshal(src interface{}) error

Marshal encodes struct into AVPs

func (*Message) NewAVP

func (m *Message) NewAVP(code interface{}, flags uint8, vendor uint32, data datatype.Type) (*AVP, error)

NewAVP creates and initializes a new AVP and adds it to the Message. It is not safe for concurrent calls.

func (*Message) Serialize

func (m *Message) Serialize() ([]byte, error)

Serialize returns the serialized bytes of the Message.

func (*Message) SerializeTo

func (m *Message) SerializeTo(b []byte) (err error)

SerializeTo writes the serialized bytes of the Message into b.

func (*Message) String

func (m *Message) String() string

func (*Message) Unmarshal

func (m *Message) Unmarshal(dst interface{}) error

Unmarshal stores the result of a diameter message in the struct pointed to by dst.

Unmarshal can not only decode AVPs into the struct, but also their Go equivalent data types, directly.

For example:

type CER struct {
	OriginHost  AVP    `avp:"Origin-Host"`
	.. or
	OriginHost  *AVP   `avp:"Origin-Host"`
	.. or
	OriginHost  string `avp:"Origin-Host"`
}
var d CER
err := diam.Unmarshal(&d)

This decodes the Origin-Host AVP as three different types. The first, AVP, makes a copy of the AVP in the message and stores in the struct. The second, *AVP, stores a pointer to the original AVP in the message. If you change the values of it, you're actually changing the message. The third decodes the inner contents of AVP.Data, which in this case is a format.DiameterIdentity, and stores the value of it in the struct.

Unmarshal supports all the basic Go types, including slices, for multiple AVPs of the same type) and structs, for grouped AVPs.

Slices:

type CER struct {
	Vendors  []*AVP `avp:"Supported-Vendor-Id"`
}
var d CER
err := diam.Unmarshal(&d)

Slices have the same principles of other types. If they're of type []*AVP it'll store references in the struct, while []AVP makes copies and []int (or []string, etc) decodes the AVP data for you.

Grouped AVPs:

type VSA struct {
	AuthAppID int `avp:"Auth-Application-Id"`
	VendorID  int `avp:"Vendor-Id"`
}
type CER struct {
	VSA VSA  `avp:"Vendor-Specific-Application-Id"`
	.. or
	VSA *VSA `avp:"Vendor-Specific-Application-Id"`
	.. or
	VSA struct {
		AuthAppID int `avp:"Auth-Application-Id"`
		VendorID  int `avp:"Vendor-Id"`
	} `avp:"Vendor-Specific-Application-Id"`
}
var d CER
err := m.Unmarshal(&d)

Other types are supported as well, such as net.IP and time.Time where applicable. See the format sub-package for details. Usually, you want to decode values to their native Go type when the AVPs don't have to be re-used in an answer, such as Origin-Host and friends. The ones that are usually added to responses, such as Origin-State-Id are better decoded to just AVP or *AVP, making it easier to re-use them in the answer.

Note that decoding values to *AVP is much faster and more efficient than decoding to AVP or the native Go types.

func (*Message) WriteTo

func (m *Message) WriteTo(writer io.Writer) (int64, error)

WriteTo serializes the Message and writes into the writer.

type ServeMux

type ServeMux struct {
	// contains filtered or unexported fields
}

ServeMux is a diameter message multiplexer. It matches the command from the incoming message against a list of registered commands and calls the handler.

func NewServeMux

func NewServeMux() *ServeMux

NewServeMux allocates and returns a new ServeMux.

func (*ServeMux) Error

func (mux *ServeMux) Error(err *ErrorReport)

Error implements the ErrorReporter interface.

func (*ServeMux) ErrorReports

func (mux *ServeMux) ErrorReports() <-chan *ErrorReport

ErrorReports implement the ErrorReporter interface.

func (*ServeMux) Handle

func (mux *ServeMux) Handle(shortCmd string, handler Handler)

Handle registers the handler for the given code. If a handler already exists for code, Handle panics.

func (*ServeMux) HandleFunc

func (mux *ServeMux) HandleFunc(cmd string, handler func(Conn, *Message))

HandleFunc registers the handler function for the given command. Special cmd "ALL" may be used as a catch all.

func (*ServeMux) HandleIdx

func (mux *ServeMux) HandleIdx(cmd CommandIndex, handler Handler)

Handle registers the handler for the given code. If a handler already exists for code, Handle panics.

func (*ServeMux) ServeDIAM

func (mux *ServeMux) ServeDIAM(c Conn, m *Message)

ServeDIAM dispatches the request to the handler that match the code in the incoming message. If the special "ALL" handler is registered it is used as a catch-all. Otherwise an ErrorReport is sent out.

type Server

type Server struct {
	Network      string        // network of the address - empty string defaults to tcp
	Addr         string        // address to listen on, ":3868" if empty
	Handler      Handler       // handler to invoke, DefaultServeMux if nil
	Dict         *dict.Parser  // diameter dictionaries for this server
	ReadTimeout  time.Duration // maximum duration before timing out read of the request
	WriteTimeout time.Duration // maximum duration before timing out write of the response
	TLSConfig    *tls.Config   // optional TLS config, used by ListenAndServeTLS
}

A Server defines parameters for running a diameter server.

func (*Server) ListenAndServe

func (srv *Server) ListenAndServe() error

ListenAndServe listens on the network address srv.Addr and then calls Serve to handle requests on incoming connections. If

If srv.Network is blank, "tcp" is used If srv.Addr is blank, ":3868" is used.

func (*Server) ListenAndServeTLS

func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error

ListenAndServeTLS listens on the network address srv.Addr and then calls Serve to handle requests on incoming TLS connections.

Filenames containing a certificate and matching private key for the server must be provided. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate followed by the CA's certificate.

If srv.Network is blank, "tcp" is used If srv.Addr is blank, ":3868" is used.

func (*Server) Serve

func (srv *Server) Serve(l net.Listener) error

Serve accepts incoming connections on the Listener l, creating a new service goroutine for each. The service goroutines read requests and then call srv.Handler to reply to them.

Directories

Path Synopsis
Package avp provides Diameter AVP constants and flags.
Package avp provides Diameter AVP constants and flags.
Package datatype provides data types for Diameter AVPs.
Package datatype provides data types for Diameter AVPs.
Package diamtest provides utilities for Diameter testing.
Package diamtest provides utilities for Diameter testing.
Package dict provides a Diameter dictionary parser.
Package dict provides a Diameter dictionary parser.
sm
Package sm provides diameter state machines for clients and servers.
Package sm provides diameter state machines for clients and servers.
smparser
Package smparser provides message parsers for the state machine.
Package smparser provides message parsers for the state machine.
smpeer
Package smpeer provides functions for extracting information from a CER or CEA, and associating with a Context.
Package smpeer provides functions for extracting information from a CER or CEA, and associating with a Context.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL