1 module snmp.agent; 2 3 import c.net_snmp; 4 import c.net_snmp_agent; 5 import snmp.types; 6 7 private alias size_t = object.size_t; 8 import snmp.oid; 9 10 /// Auth-protocol OID pointers exported by net-snmp. 11 struct AuthProto 12 { 13 static const(oid)* md5() @trusted @nogc nothrow { return usmHMACMD5AuthProtocol.ptr; } 14 static const(oid)* sha1() @trusted @nogc nothrow { return usmHMACSHA1AuthProtocol.ptr; } 15 static size_t md5Len() @trusted @nogc nothrow { return usmHMACMD5AuthProtocol.length; } 16 static size_t sha1Len() @trusted @nogc nothrow { return usmHMACSHA1AuthProtocol.length; } 17 } 18 19 struct PrivProto 20 { 21 static const(oid)* des() @trusted @nogc nothrow { return usmDESPrivProtocol.ptr; } 22 static const(oid)* aes() @trusted @nogc nothrow { return usmAESPrivProtocol.ptr; } 23 static size_t desLen() @trusted @nogc nothrow { return usmDESPrivProtocol.length; } 24 static size_t aesLen() @trusted @nogc nothrow { return usmAESPrivProtocol.length; } 25 } 26 27 /// Passed to scalar handler callbacks; wraps value-setting for the response. 28 struct ScalarRequest 29 { 30 netsnmp_agent_request_info* reqinfo; 31 netsnmp_request_info* requests; 32 33 bool isGet() const @trusted @nogc nothrow 34 { 35 return reqinfo !is null && reqinfo.mode == cast(int) PDUType.get; 36 } 37 38 /// Counter32 (wrapping 32-bit unsigned counter). 39 void setCounter(uint val) @trusted @nogc nothrow 40 { 41 setValue(cast(int) ASNType.counter32, &val, val.sizeof); 42 } 43 44 /// Gauge32 (non-wrapping unsigned integer). 45 void setGauge(uint val) @trusted @nogc nothrow 46 { 47 setValue(cast(int) ASNType.gauge32, &val, val.sizeof); 48 } 49 50 /// TimeTicks (hundredths of a second since some epoch). 51 void setTimeTicks(uint val) @trusted @nogc nothrow 52 { 53 setValue(cast(int) ASNType.timeticks, &val, val.sizeof); 54 } 55 56 /// Integer (signed 32-bit). 57 void setInteger(int val) @trusted @nogc nothrow 58 { 59 long v = val; 60 setValue(cast(int) ASNType.integer, &v, v.sizeof); 61 } 62 63 /// OctetString (bytes, string data, IP address, etc.). 64 void setOctetStr(scope const(ubyte)[] val) @trusted @nogc nothrow 65 { 66 if (val !is null) 67 setValue(cast(int) ASNType.octetStr, val.ptr, val.length); 68 } 69 70 /// Counter64. 71 void setCounter64(counter64 val) @trusted @nogc nothrow 72 { 73 setValue(cast(int) ASNType.counter64, &val, val.sizeof); 74 } 75 76 private void setValue(int asnType, scope const(void)* valPtr, size_t len) @trusted @nogc nothrow 77 { 78 if (!requests) 79 return; 80 snmp_set_var_typed_value(cast(netsnmp_variable_list*) requests.requestvb, 81 cast(ubyte) asnType, valPtr, cast(ulong) len); 82 } 83 } 84 85 /// Embedded SNMP agent or AgentX subagent (RAII, non-copyable). 86 struct SNMPAgent 87 { 88 private const(char)* _name; 89 bool initialised; 90 91 @disable this(this); 92 93 /// `name` must outlive the agent. 94 static SNMPAgent create(scope const(char)* name, 95 bool agentx = false) @trusted @nogc nothrow 96 { 97 SNMPAgent a; 98 if (!name) 99 return a; 100 101 if (agentx) 102 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); 103 104 init_snmp(name); 105 int rc = init_agent(name); 106 if (rc == 0) 107 { 108 a._name = name; 109 a.initialised = true; 110 } 111 return a; 112 } 113 114 ~this() @trusted @nogc nothrow { shutdown(); } 115 116 void shutdown() @trusted @nogc nothrow 117 { 118 if (initialised) 119 { 120 snmp_shutdown(_name); 121 _name = null; 122 initialised = false; 123 } 124 } 125 126 bool isReady() const @nogc nothrow @safe 127 { 128 return initialised; 129 } 130 131 /// Register a read-only scalar OID. net-snmp copies the OID internally. 132 bool registerScalar(const(char)* name, Netsnmp_Node_Handler* fn, 133 scope const OID o) @trusted @nogc nothrow 134 { 135 if (!initialised || !name || !fn || !o.isValid) 136 return false; 137 auto reg = netsnmp_create_handler_registration( 138 name, fn, o.data.ptr, o.length, HANDLER_CAN_RONLY); 139 if (!reg) 140 return false; 141 return netsnmp_register_scalar(reg) == 0; 142 } 143 144 /// Process one round of pending requests. 145 /// block=true waits until a request arrives; false returns immediately. 146 void process(bool block = true) @trusted @nogc nothrow 147 { 148 if (initialised) 149 agent_check_and_process(block ? 1 : 0); 150 } 151 } 152 153 unittest 154 { 155 auto agent = SNMPAgent.create("snmp-d-agent-test"); 156 agent.shutdown(); 157 assert(!agent.isReady); 158 159 agent.shutdown(); 160 assert(!agent.isReady); 161 }