186 lines
5.0 KiB
Go
186 lines
5.0 KiB
Go
// Copyright 2018 The agentx authors
|
|
// Licensed under the LGPLv3 with static-linking exception.
|
|
// See LICENCE file for details.
|
|
|
|
package agentx
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/posteo/go-agentx/pdu"
|
|
"github.com/posteo/go-agentx/value"
|
|
)
|
|
|
|
// Session defines an agentx session.
|
|
type Session struct {
|
|
Handler Handler
|
|
|
|
client *Client
|
|
sessionID uint32
|
|
timeout time.Duration
|
|
|
|
openRequestPacket *pdu.HeaderPacket
|
|
registerRequestPacket *pdu.HeaderPacket
|
|
}
|
|
|
|
// ID returns the session id.
|
|
func (s *Session) ID() uint32 {
|
|
return s.sessionID
|
|
}
|
|
|
|
// Register registers the client under the provided rootID with the provided priority
|
|
// on the master agent.
|
|
func (s *Session) Register(priority byte, baseOID value.OID) error {
|
|
if s.registerRequestPacket != nil {
|
|
return fmt.Errorf("session is already registered")
|
|
}
|
|
|
|
requestPacket := &pdu.Register{}
|
|
requestPacket.Timeout.Duration = s.timeout
|
|
requestPacket.Timeout.Priority = priority
|
|
requestPacket.Subtree.SetIdentifier(baseOID)
|
|
request := &pdu.HeaderPacket{Header: &pdu.Header{Type: pdu.TypeRegister}, Packet: requestPacket}
|
|
|
|
response := s.request(request)
|
|
if err := checkError(response); err != nil {
|
|
return err
|
|
}
|
|
s.registerRequestPacket = request
|
|
return nil
|
|
}
|
|
|
|
// Unregister removes the registration for the provided subtree.
|
|
func (s *Session) Unregister(priority byte, baseOID value.OID) error {
|
|
if s.registerRequestPacket == nil {
|
|
return fmt.Errorf("session is not registered")
|
|
}
|
|
|
|
requestPacket := &pdu.Unregister{}
|
|
requestPacket.Timeout.Duration = s.timeout
|
|
requestPacket.Timeout.Priority = priority
|
|
requestPacket.Subtree.SetIdentifier(baseOID)
|
|
request := &pdu.HeaderPacket{Header: &pdu.Header{}, Packet: requestPacket}
|
|
|
|
response := s.request(request)
|
|
if err := checkError(response); err != nil {
|
|
return err
|
|
}
|
|
s.registerRequestPacket = nil
|
|
return nil
|
|
}
|
|
|
|
// Close tears down the session with the master agent.
|
|
func (s *Session) Close() error {
|
|
requestPacket := &pdu.Close{Reason: pdu.ReasonShutdown}
|
|
|
|
response := s.request(&pdu.HeaderPacket{Header: &pdu.Header{}, Packet: requestPacket})
|
|
if err := checkError(response); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Session) open(nameOID value.OID, name string) error {
|
|
requestPacket := &pdu.Open{}
|
|
requestPacket.Timeout.Duration = s.timeout
|
|
requestPacket.ID.SetIdentifier(nameOID)
|
|
requestPacket.Description.Text = name
|
|
request := &pdu.HeaderPacket{Header: &pdu.Header{Type: pdu.TypeOpen}, Packet: requestPacket}
|
|
|
|
response := s.request(request)
|
|
if err := checkError(response); err != nil {
|
|
return err
|
|
}
|
|
s.sessionID = response.Header.SessionID
|
|
s.openRequestPacket = request
|
|
return nil
|
|
}
|
|
|
|
func (s *Session) reopen() error {
|
|
if s.openRequestPacket != nil {
|
|
response := s.request(s.openRequestPacket)
|
|
if err := checkError(response); err != nil {
|
|
return err
|
|
}
|
|
s.sessionID = response.Header.SessionID
|
|
}
|
|
|
|
if s.registerRequestPacket != nil {
|
|
response := s.request(s.registerRequestPacket)
|
|
if err := checkError(response); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Session) request(hp *pdu.HeaderPacket) *pdu.HeaderPacket {
|
|
hp.Header.SessionID = s.sessionID
|
|
return s.client.request(hp)
|
|
}
|
|
|
|
func (s *Session) handle(request *pdu.HeaderPacket) *pdu.HeaderPacket {
|
|
responseHeader := &pdu.Header{}
|
|
responseHeader.SessionID = request.Header.SessionID
|
|
responseHeader.TransactionID = request.Header.TransactionID
|
|
responseHeader.PacketID = request.Header.PacketID
|
|
responsePacket := &pdu.Response{}
|
|
|
|
switch requestPacket := request.Packet.(type) {
|
|
case *pdu.Get:
|
|
if s.Handler == nil {
|
|
log.Printf("warning: no handler for session specified")
|
|
responsePacket.Variables.Add(requestPacket.GetOID(), pdu.VariableTypeNull, nil)
|
|
} else {
|
|
oid, t, v, err := s.Handler.Get(requestPacket.GetOID())
|
|
if err != nil {
|
|
log.Printf("error while handling packet: %v", err)
|
|
responsePacket.Error = pdu.ErrorProcessing
|
|
}
|
|
if oid == nil {
|
|
responsePacket.Variables.Add(requestPacket.GetOID(), pdu.VariableTypeNoSuchObject, nil)
|
|
} else {
|
|
responsePacket.Variables.Add(oid, t, v)
|
|
}
|
|
}
|
|
case *pdu.GetNext:
|
|
if s.Handler == nil {
|
|
log.Printf("warning: no handler for session specified")
|
|
} else {
|
|
for _, sr := range requestPacket.SearchRanges {
|
|
oid, t, v, err := s.Handler.GetNext(sr.From.GetIdentifier(), (sr.From.Include == 1), sr.To.GetIdentifier())
|
|
if err != nil {
|
|
log.Printf("error while handling packet: %v", err)
|
|
responsePacket.Error = pdu.ErrorProcessing
|
|
}
|
|
|
|
if oid == nil {
|
|
responsePacket.Variables.Add(sr.From.GetIdentifier(), pdu.VariableTypeEndOfMIBView, nil)
|
|
} else {
|
|
responsePacket.Variables.Add(oid, t, v)
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
log.Printf("cannot handle unrequested packet: %v", request)
|
|
responsePacket.Error = pdu.ErrorProcessing
|
|
}
|
|
|
|
return &pdu.HeaderPacket{Header: responseHeader, Packet: responsePacket}
|
|
}
|
|
|
|
func checkError(hp *pdu.HeaderPacket) error {
|
|
response, ok := hp.Packet.(*pdu.Response)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
if response.Error == pdu.ErrorNone {
|
|
return nil
|
|
}
|
|
return errors.New(response.Error.String())
|
|
}
|