1 module snmp.varbind; 2 3 import c.net_snmp; 4 import snmp.oid : OID; 5 6 private alias size_t = object.size_t; 7 8 /// Cursor over a netsnmp_variable_list linked list. 9 struct VarBind 10 { 11 netsnmp_variable_list* handle; 12 13 bool isValid() const @nogc nothrow @safe 14 { 15 return handle !is null; 16 } 17 18 VarBind next() const @trusted @nogc nothrow 19 { 20 return handle 21 ? VarBind(cast(netsnmp_variable_list*) handle.next_variable) : VarBind(null); 22 } 23 24 const(oid)* namePtr() const @trusted @nogc nothrow 25 { 26 return handle ? handle.name : null; 27 } 28 29 size_t nameLength() const @trusted @nogc nothrow 30 { 31 return handle ? handle.name_length : 0; 32 } 33 34 ubyte type() const @trusted @nogc nothrow 35 { 36 return handle ? handle.type : 0; 37 } 38 39 int valueStr(scope char[] buf) const @trusted @nogc nothrow 40 { 41 if (!isValid || buf.length == 0) 42 return 0; 43 auto h = cast(netsnmp_variable_list*) handle; 44 return snprint_value(buf.ptr, buf.length, h.name, h.name_length, h); 45 } 46 47 int oidStr(scope char[] buf) const @trusted @nogc nothrow 48 { 49 if (!isValid || buf.length == 0) 50 return 0; 51 return snprint_objid(buf.ptr, buf.length, handle.name, handle.name_length); 52 } 53 54 string oidString() const @trusted nothrow 55 { 56 char[512] buf = void; 57 int n = oidStr(buf[]); 58 return n > 0 ? buf[0 .. n].idup : ""; 59 } 60 61 string valueString() const @trusted nothrow 62 { 63 char[512] buf = void; 64 int n = valueStr(buf[]); 65 return n > 0 ? buf[0 .. n].idup : ""; 66 } 67 68 OID toOID() const @trusted @nogc nothrow 69 { 70 import core.stdc.string : memcpy; 71 72 OID o; 73 if (!isValid) 74 return o; 75 o.length = handle.name_length < MAX_OID_LEN ? handle.name_length : MAX_OID_LEN; 76 memcpy(o.data.ptr, handle.name, o.length * oid.sizeof); 77 return o; 78 } 79 80 /// Returns 0 for non-integer or invalid bindings. 81 long asLong() const @trusted @nogc nothrow 82 { 83 if (!isValid || handle.type != ASN_INTEGER || !handle.val.integer) 84 return 0; 85 return *handle.val.integer; 86 } 87 88 /// Counter32 / Gauge32 / TimeTicks. Returns 0 on type mismatch. 89 uint asUint() const @trusted @nogc nothrow 90 { 91 if (!isValid || !handle.val.integer) 92 return 0; 93 ubyte t = handle.type; 94 if (t != ASN_COUNTER && t != ASN_GAUGE && t != ASN_TIMETICKS && t != ASN_UNSIGNED) 95 return 0; 96 return cast(uint) *handle.val.integer; 97 } 98 99 /// Returns zeroed struct on type mismatch. 100 counter64 asCounter64() const @trusted @nogc nothrow 101 { 102 counter64 zero; 103 if (!isValid || handle.type != ASN_COUNTER64 || !handle.val.counter64) 104 return zero; 105 return *handle.val.counter64; 106 } 107 108 /// OctetStr / IpAddress / BitStr raw bytes. Returns null on type mismatch. 109 const(ubyte)[] asBytes() const @trusted @nogc nothrow 110 { 111 if (!isValid) 112 return null; 113 ubyte t = handle.type; 114 if (t != ASN_OCTET_STR && t != ASN_IPADDRESS && t != ASN_BIT_STR) 115 return null; 116 // `string` is a D keyword — access via __traits 117 auto p = __traits(getMember, handle.val, "string"); 118 if (!p) 119 return null; 120 return p[0 .. handle.val_len]; 121 } 122 123 int opApply(scope int delegate(VarBind) dg) 124 { 125 for (auto v = this; v.isValid; v = v.next) 126 if (auto r = dg(v)) 127 return r; 128 return 0; 129 } 130 } 131 132 unittest 133 { 134 VarBind v; 135 assert(!v.isValid); 136 assert(!v.next.isValid); 137 assert(v.namePtr is null); 138 assert(v.nameLength == 0); 139 assert(v.type == 0); 140 141 char[64] buf; 142 assert(v.valueStr(buf[]) == 0); 143 assert(v.oidStr(buf[]) == 0); 144 assert(v.oidString == ""); 145 assert(v.valueString == ""); 146 147 assert(!v.toOID.isValid); 148 assert(v.asLong == 0); 149 assert(v.asUint == 0); 150 assert(v.asBytes is null); 151 counter64 zero; 152 assert(v.asCounter64.high == zero.high && v.asCounter64.low == zero.low); 153 }