// 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()) }