Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions snmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"math/rand"
"net"
"os"
"reflect"
"time"
)
Expand All @@ -15,6 +16,7 @@ type WapSNMP struct {
Target string // Target device for these SNMP events.
Community string // Community to use to contact the device.
Version SNMPVersion // SNMPVersion to encode in the packets.
Logger *log.Logger // Logger to use for all SNMP-related messages
timeout time.Duration // Timeout to use for all SNMP packets.
retries int // Number of times to retry an operation.
conn net.Conn // Cache the UDP connection in the object.
Expand All @@ -24,21 +26,25 @@ const (
bufSize int = 16384
)

func newDefaultLogger() *log.Logger {
return log.New(os.Stderr, "[SNMP] ", log.LstdFlags)
}

// NewWapSNMP creates a new WapSNMP object. Opens a udp connection to the device that will be used for the SNMP packets.
func NewWapSNMP(target, community string, version SNMPVersion, timeout time.Duration, retries int) (*WapSNMP, error) {
targetPort := fmt.Sprintf("%s:161", target)
conn, err := net.DialTimeout("udp", targetPort, timeout)
if err != nil {
return nil, fmt.Errorf(`error connecting to ("udp", "%s") : %s`, targetPort, err)
}
return &WapSNMP{target, community, version, timeout, retries, conn}, nil
return &WapSNMP{target, community, version, newDefaultLogger(), timeout, retries, conn}, nil
}

// NewWapSNMPOnConn creates a new WapSNMP object from an existing net.Conn.
//
// It does not check if the provided target is valid.
func NewWapSNMPOnConn(target, community string, version SNMPVersion, timeout time.Duration, retries int, conn net.Conn) *WapSNMP {
return &WapSNMP{target, community, version, timeout, retries, conn}
return &WapSNMP{target, community, version, newDefaultLogger(), timeout, retries, conn}
}

// Generate a valid SNMP request ID.
Expand All @@ -47,29 +53,29 @@ func getRandomRequestID() int {
}

// poll sends a packet and wait for a response. Both operations can timeout, they're retried up to retries times.
func poll(conn net.Conn, toSend []byte, respondBuffer []byte, retries int, timeout time.Duration) (int, error) {
func poll(conn net.Conn, toSend []byte, respondBuffer []byte, retries int, timeout time.Duration, logger *log.Logger) (int, error) {
var err error
for i := 0; i < retries+1; i++ {
deadline := time.Now().Add(timeout)

if err = conn.SetWriteDeadline(deadline); err != nil {
log.Printf("Couldn't set write deadline. Retrying. Retry %d/%d\n", i, retries)
logger.Printf("Couldn't set write deadline. Retrying. Retry %d/%d\n", i, retries)
continue
}
if _, err = conn.Write(toSend); err != nil {
log.Printf("Couldn't write. Retrying. Retry %d/%d\n", i, retries)
logger.Printf("Couldn't write. Retrying. Retry %d/%d\n", i, retries)
continue
}

deadline = time.Now().Add(timeout)
if err = conn.SetReadDeadline(deadline); err != nil {
log.Printf("Couldn't set read deadline. Retrying. Retry %d/%d\n", i, retries)
logger.Printf("Couldn't set read deadline. Retrying. Retry %d/%d\n", i, retries)
continue
}

numRead := 0
if numRead, err = conn.Read(respondBuffer); err != nil {
log.Printf("Couldn't read. Retrying. Retry %d/%d\n", i, retries)
logger.Printf("Couldn't read. Retrying. Retry %d/%d\n", i, retries)
continue
}

Expand All @@ -90,7 +96,7 @@ func (w WapSNMP) Get(oid Oid) (interface{}, error) {
}

response := make([]byte, bufSize, bufSize)
numRead, err := poll(w.conn, req, response, w.retries, 500*time.Millisecond)
numRead, err := poll(w.conn, req, response, w.retries, 500*time.Millisecond, w.Logger)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -124,7 +130,7 @@ func (w WapSNMP) GetMultiple(oids []Oid) (map[string]interface{}, error) {
}

response := make([]byte, bufSize, bufSize)
numRead, err := poll(w.conn, req, response, w.retries, 500*time.Millisecond)
numRead, err := poll(w.conn, req, response, w.retries, 500*time.Millisecond, w.Logger)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -160,7 +166,7 @@ func (w WapSNMP) GetNext(oid Oid) (*Oid, interface{}, error) {
}

response := make([]byte, bufSize)
numRead, err := poll(w.conn, req, response, w.retries, 500*time.Millisecond)
numRead, err := poll(w.conn, req, response, w.retries, 500*time.Millisecond, w.Logger)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -196,7 +202,7 @@ func (w WapSNMP) GetBulk(oid Oid, maxRepetitions int) (map[string]interface{}, e
}

response := make([]byte, bufSize, bufSize)
numRead, err := poll(w.conn, req, response, w.retries, 500*time.Millisecond)
numRead, err := poll(w.conn, req, response, w.retries, 500*time.Millisecond, w.Logger)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -225,7 +231,7 @@ func (w WapSNMP) GetTable(oid Oid) (map[string]interface{}, error) {
result := make(map[string]interface{})
lastOid := oid.Copy()
for lastOid.Within(oid) {
log.Printf("Sending GETBULK(%v, 50)\n", lastOid)
w.Logger.Printf("Sending GETBULK(%v, 50)\n", lastOid)
results, err := w.GetBulk(lastOid, 50)
if err != nil {
return nil, fmt.Errorf("received GetBulk error => %v\n", err)
Expand Down