Merge branch 'master' into jwi-bcc64xsingletonwarning
[ACE_TAO.git] / ACE / ASNMP / asnmp / wpdu.cpp
blob1685d9190d2b882285f8fd578646d191a41493ad
2 //=============================================================================
3 /**
4 * @file wpdu.cpp
6 * Adapter class. Converts between raw wire format and Pdu objects
7 * that can be stuffed out a I/O port or reconstructed
9 * @author Michael R. MacFaden rework the class api and impl using ACEPeter E Mellquist implementation/code from snmp++ snmpmsg class
11 //=============================================================================
14 #include "asnmp/wpdu.h"
15 #include "ace/Log_Msg.h"
16 #include "ace/OS_NS_string.h"
17 #include "ace/OS_NS_stdio.h"
19 #define DEFINE_TRAP_CONSTANTS_
20 #include "asnmp/enttraps.h"
22 #define MAX_COMM_STR_LEN 255
23 #define V1_COLD_START 0
24 #define V1_WARM_START 1
25 #define V1_LINK_DOWN 2
26 #define V1_LINK_UP 3
27 #define V1_AUTH_FAILURE 4
28 #define V1_EGP_NEIGHBOR_LOSS 5
29 #define V1_ENT_SPECIFIC 6
31 inline
32 void reset_iov(iovec& iov)
34 iov.iov_base = 0;
35 iov.iov_len = 0;
38 wpdu::wpdu(const Pdu& pdu, const UdpTarget& target):
39 valid_flag_(SNMP_CLASS_INVALID ), comm_len(MAX_COMM_STR_LEN)
41 reset_iov(iovec_);
42 version_ = target.get_version();
43 int status;
44 OctetStr comm_str;
46 community_name[0] = 0;
48 snmp_pdu *raw_pdu; // create a raw pdu
49 raw_pdu = cmu_snmp::pdu_create( (int) pdu.get_type());
50 if (!raw_pdu) {
51 valid_flag_ = SNMP_CLASS_RESOURCE_UNAVAIL;
52 return;
55 raw_pdu->reqid = pdu.get_request_id();
56 raw_pdu->errstat= (unsigned long) pdu.get_error_status();
57 raw_pdu->errindex= (unsigned long) pdu.get_error_index();
59 switch (raw_pdu->command) {
60 case sNMP_PDU_GET:
61 case sNMP_PDU_GETNEXT:
62 target.get_read_community(comm_str);
63 break;
65 case sNMP_PDU_SET:
66 target.get_write_community(comm_str);
67 break;
69 case sNMP_PDU_V1TRAP:
70 target.get_read_community(comm_str);
71 if (set_trap_info(raw_pdu, pdu)) // will free raw_pdu
72 return;
73 break;
74 case sNMP_PDU_RESPONSE:
75 break;
77 default:
78 ACE_ASSERT(0);
79 return;
82 if (load_vbs(raw_pdu, pdu)) {
83 cmu_snmp::free_pdu( raw_pdu);
84 valid_flag_ = SNMP_CLASS_RESOURCE_UNAVAIL;
85 return;
88 // TODO: determine how big raw_pdu serializes out to
89 iovec_.iov_len = target.get_max_pdu_size();
90 ACE_NEW(iovec_.iov_base, char [iovec_.iov_len]);
92 // create raw byte stream
93 // The intermediate integer is to avoid type-punned pointer
94 // dereferencing.
95 int out_length = iovec_.iov_len;
96 status = cmu_snmp::build( raw_pdu,
97 (unsigned char *)iovec_.iov_base,
98 &out_length,
99 target.get_version(),
100 comm_str.data(),
101 comm_str.length());
102 iovec_.iov_len = out_length;
104 if ( status != 0) {
105 valid_flag_ = SNMP_ERROR_WRONG_ENCODING;
106 cmu_snmp::free_pdu( raw_pdu);
107 return;
110 cmu_snmp::free_pdu( raw_pdu);
111 valid_flag_ = SNMP_CLASS_SUCCESS;
114 int wpdu::set_trap_info(snmp_pdu *raw_pdu, const Pdu& pdu) const
116 Oid enterprise;
117 Oid trapid; // validate caller has set this correctly
118 pdu.get_notify_id( trapid);
119 if ( !trapid.valid() || trapid.length() < 2 ) {
120 cmu_snmp::free_pdu( raw_pdu);
121 return SNMP_CLASS_INVALID_NOTIFYID;
124 raw_pdu->specific_type=0;
126 // TODO: object should emit numeric instead of this kind of mess...
127 if ( trapid == coldStart)
128 raw_pdu->trap_type = V1_COLD_START; // cold start
129 else if ( trapid == warmStart)
130 raw_pdu->trap_type = V1_WARM_START; // warm start
131 else if( trapid == linkDown)
132 raw_pdu->trap_type = V1_LINK_DOWN; // link down
133 else if ( trapid == linkUp)
134 raw_pdu->trap_type = V1_LINK_UP; // link up
135 else if ( trapid == authenticationFailure )
136 raw_pdu->trap_type = V1_AUTH_FAILURE; // authentication failure
137 else if ( trapid == egpNeighborLoss)
138 raw_pdu->trap_type = V1_EGP_NEIGHBOR_LOSS; // egp neighbor loss
139 else {
140 raw_pdu->trap_type = V1_ENT_SPECIFIC; // enterprise specific
141 // last oid subid is the specific value
142 // if 2nd to last subid is "0", remove it
143 // enterprise is always the notify oid prefix
144 raw_pdu->specific_type = (int) trapid[(int) (trapid.length() - 1)];
145 trapid.trim(1);
146 if ( trapid[(int)(trapid.length() - 1)] == 0 )
147 trapid.trim(1);
148 enterprise = trapid;
151 if ( raw_pdu->trap_type != V1_ENT_SPECIFIC)
152 pdu.get_notify_enterprise( enterprise);
153 if ( enterprise.length() > 0) {
154 // note!! To the contrary, enterprise OID val is
155 // copied here and raw_pdu->enterprise is freed in free_pdu
156 // as it should be (HDN)
157 // these are hooks into an SNMP++ oid
158 // and therefor the raw_pdu enterprise
159 // should not free them. null them out!!
160 SmiLPOID rawOid;
161 rawOid = enterprise.oidval();
162 // HDN - enterprise is a local object, cannot simply assign pointer
163 //raw_pdu->enterprise = rawOid->ptr;
164 raw_pdu->enterprise_length = (int) rawOid->len;
165 ACE_NEW_RETURN(raw_pdu->enterprise,
166 oid[raw_pdu->enterprise_length],-1);
167 ACE_OS::memcpy((char *)raw_pdu->enterprise,(char *)rawOid->ptr,
168 raw_pdu->enterprise_length * sizeof(oid));
171 TimeTicks timestamp;
172 pdu.get_notify_timestamp( timestamp);
173 raw_pdu->time = ( unsigned long) timestamp;
175 // HDN - set agent addr using the local hostname if possible
176 char localHostName[MAXHOSTNAMELEN];
177 Snmp::get_host_name(localHostName, MAXHOSTNAMELEN);
178 if (ACE_OS::strlen(localHostName) > 0) {
179 GenAddress addr(localHostName);
180 OctetStr octet;
181 addr.to_octet(octet);
182 ACE_OS::memcpy(&(raw_pdu->agent_addr.sin_addr),
183 octet.data(),
184 octet.length());
187 return 0;
190 wpdu::wpdu(const iovec& iov): valid_flag_(0),comm_len(MAX_COMM_STR_LEN)
192 community_name[0] = 0;
193 reset_iov(iovec_);
194 version_ = version1; // TODO: figure where this should come from
195 ACE_NEW(iovec_.iov_base, char[iov.iov_len]);
196 if (!iovec_.iov_base) {
197 valid_flag_ = SNMP_CLASS_RESOURCE_UNAVAIL;
198 return;
201 copy_iovec(iovec_, iov);
202 valid_flag_ = SNMP_CLASS_SUCCESS;
205 wpdu::wpdu(): valid_flag_(0), comm_len(MAX_COMM_STR_LEN)
207 community_name[0] = 0;
208 reset_iov(iovec_);
209 version_ = version1; // TODO: figure where this should come from
212 int wpdu::valid() const
214 return (valid_flag_ == SNMP_CLASS_SUCCESS);
217 int wpdu::load_vbs(snmp_pdu *raw_pdu, const Pdu& pdu)
219 int status = 0;
221 // load up the payload
222 // for all Vbs in list, add them to the pdu
223 int vb_count;
224 Vb tempvb;
225 Oid tempoid;
226 SmiLPOID smioid;
227 SmiVALUE smival;
229 vb_count = pdu.get_vb_count();
231 for (int z = 0; z < vb_count; z++) {
232 pdu.get_vb( tempvb, z);
233 tempvb.get_oid( tempoid);
234 smioid = tempoid.oidval();
235 // what are we trying to convert here (vb oid part or value part)
236 status = convert_vb_to_smival( tempvb, &smival );
237 if ( status != SNMP_CLASS_SUCCESS)
238 return status;
240 // add the var to the raw pdu
241 cmu_snmp::add_var(raw_pdu, smioid->ptr, (int) smioid->len, &smival);
242 free_smival_descriptor( &smival);
245 return status;
248 // supports overlapped copies
249 // static
250 void wpdu::copy_iovec(iovec& dest, const iovec& src)
252 if (&dest == &src)
253 return;
255 ACE_OS::memmove( dest.iov_base, src.iov_base, src.iov_len);
256 dest.iov_len = src.iov_len;
259 int wpdu::convert_vb_to_smival( Vb &tempvb, SmiVALUE *smival )
261 smival->syntax = tempvb.get_syntax();
263 switch ( smival->syntax ) {
264 case sNMP_SYNTAX_NULL:
265 break;
267 // case sNMP_SYNTAX_INT32:
268 case sNMP_SYNTAX_INT:
270 SnmpInt32 tmp;
271 tempvb.get_value(tmp);
272 smival->value.sNumber = tmp;
274 break;
276 // case sNMP_SYNTAX_UINT32:
277 case sNMP_SYNTAX_GAUGE32:
278 case sNMP_SYNTAX_CNTR32:
279 case sNMP_SYNTAX_TIMETICKS:
281 SnmpUInt32 tmp;
282 tempvb.get_value(tmp);
283 smival->value.uNumber = tmp;
285 break;
287 // case Counter64
288 case sNMP_SYNTAX_CNTR64:
290 Counter64 c64;
291 tempvb.get_value(c64);
292 smival->value.hNumber.hipart = c64.high();
293 smival->value.hNumber.lopart = c64.low();
295 break;
297 // OID syntax
298 case sNMP_SYNTAX_OID:
300 Oid tmpoid;
301 tmpoid.oidval();
302 tempvb.get_value(tmpoid);
303 SmiLPOID smi = tmpoid.oidval();
304 smival->value.oid.len = tmpoid.length();
305 ACE_NEW_RETURN(smival->value.oid.ptr,
306 SmiUINT32 [smival->value.oid.len], 1);
307 ACE_OS::memcpy(smival->value.oid.ptr, smi->ptr,
308 smival->value.oid.len *sizeof(SmiUINT32));
310 break;
312 case sNMP_SYNTAX_BITS:
313 case sNMP_SYNTAX_OCTETS:
314 case sNMP_SYNTAX_IPADDR:
316 OctetStr os;
317 tempvb.get_value(os);
318 smival->value.string.ptr = 0;
319 smival->value.string.len = os.length();
320 if ( smival->value.string.len > 0 ) {
321 ACE_NEW_RETURN(smival->value.string.ptr,
322 SmiBYTE [smival->value.string.len], 1);
323 if ( smival->value.string.ptr ) {
324 for (int i=0; i<(int) smival->value.string.len ; i++)
325 smival->value.string.ptr[i] = os[i];
327 else {
328 smival->syntax = sNMP_SYNTAX_NULL; // invalidate the smival
329 return SNMP_CLASS_RESOURCE_UNAVAIL;
333 break;
335 default:
336 ACE_DEBUG((LM_DEBUG, "wpdu::convert_vb_to_smival did not convert vb\n"));
337 // ACE_ASSERT(0);
338 } // switch
340 return 0;
343 // free a SMI value
344 void wpdu::free_smival_descriptor( SmiVALUE *smival )
346 switch ( smival->syntax ) {
347 case sNMP_SYNTAX_OCTETS:
348 case sNMP_SYNTAX_OPAQUE:
349 case sNMP_SYNTAX_IPADDR:
350 case sNMP_SYNTAX_BITS: // obsoleted in SNMPv2 Draft Std
351 delete [] smival->value.string.ptr;
352 break;
354 case sNMP_SYNTAX_OID:
355 delete [] smival->value.oid.ptr;
356 break;
358 smival->syntax = sNMP_SYNTAX_NULL;
362 wpdu::~wpdu()
364 delete [] (char*) iovec_.iov_base;
367 const iovec& wpdu::get_buffer() const
369 return iovec_;
372 // return a pdu from a buffer
373 int wpdu::get_pdu(Pdu& pdu, snmp_version& version)
375 if (iovec_.iov_len == 0)
376 return -1; // NO DATA
378 snmp_pdu *raw_pdu = cmu_snmp::pdu_create(0);
379 if (!raw_pdu) {
380 return SNMP_CLASS_RESOURCE_UNAVAIL;
383 // max value a client can send us - TODO: replace this with an
384 // api to get actual string length
385 int status = cmu_snmp::parse( raw_pdu, (unsigned char *)iovec_.iov_base,
386 community_name, comm_len,
387 version, iovec_.iov_len);
388 if (status != 0)
389 return SNMP_CLASS_INTERNAL_ERROR;
391 community_name[comm_len] = 0; // set null based on returned length
392 set_request_id( &pdu, raw_pdu->reqid);
393 set_error_status( &pdu, (int) raw_pdu->errstat);
394 set_error_index( &pdu, (int) raw_pdu->errindex);
395 pdu.set_type( raw_pdu->command);
397 if (restore_vbs(pdu, raw_pdu)) {
398 cmu_snmp::free_pdu(raw_pdu);
399 return SNMP_CLASS_INTERNAL_ERROR;
402 cmu_snmp::free_pdu(raw_pdu);
403 return 0;
406 int wpdu::restore_vbs(Pdu& pdu, const snmp_pdu *raw_pdu) const
408 Vb tempvb;
409 Oid tempoid;
410 struct variable_list *vp;
412 for(vp = raw_pdu->variables; vp; vp = vp->next_variable) {
413 // extract the oid portion
414 tempoid.set_data( (unsigned long *)vp->name,
415 ( unsigned int) vp->name_length);
416 tempvb.set_oid( tempoid);
418 // extract the value portion
419 switch(vp->type) {
420 // octet string
421 case sNMP_SYNTAX_OCTETS:
422 case sNMP_SYNTAX_OPAQUE:
424 OctetStr octets( (char *) vp->val.string,
425 (long) vp->val_len);
426 tempvb.set_value( octets);
428 break;
430 // object id
431 case sNMP_SYNTAX_OID:
433 Oid oid( (unsigned long*) vp->val.objid,
434 (int) vp->val_len);
435 tempvb.set_value( oid);
437 break;
439 // timeticks
440 case sNMP_SYNTAX_TIMETICKS:
442 TimeTicks timeticks( (unsigned long) *(vp->val.integer));
443 tempvb.set_value( timeticks);
445 break;
447 // Gauge32
448 case sNMP_SYNTAX_GAUGE32:
450 Gauge32 gauge32( (unsigned long) *(vp->val.integer));
451 tempvb.set_value( gauge32);
453 break;
455 // 32 bit counter
456 case sNMP_SYNTAX_CNTR32:
458 Counter32 counter32( (unsigned long) *(vp->val.integer));
459 tempvb.set_value( counter32);
461 break;
463 // ip address
464 case sNMP_SYNTAX_IPADDR:
466 char buffer[20];
467 ACE_OS::sprintf( buffer,"%d.%d.%d.%d",
468 vp->val.string[0],
469 vp->val.string[1],
470 vp->val.string[2],
471 vp->val.string[3]);
472 IpAddress ipaddress( buffer);
473 tempvb.set_value( ipaddress);
475 break;
477 // 32 bit integer
478 case sNMP_SYNTAX_INT:
480 SnmpInt32 int32( (long) *(vp->val.integer));
481 tempvb.set_value( int32);
483 break;
485 // 32 bit unsigned integer
486 case sNMP_SYNTAX_UINT32:
488 SnmpUInt32 uint32( (unsigned long) *(vp->val.integer));
489 tempvb.set_value( uint32);
491 break;
493 // v2 counter 64's
494 case sNMP_SYNTAX_CNTR64:
495 break;
497 case sNMP_SYNTAX_NULL:
498 tempvb.set_null();
499 break;
501 // v2 vb exceptions
502 case sNMP_SYNTAX_NOSUCHOBJECT:
503 case sNMP_SYNTAX_NOSUCHINSTANCE:
504 case sNMP_SYNTAX_ENDOFMIBVIEW:
505 set_exception_status( &tempvb, vp->type);
506 break;
508 default:
509 tempvb.set_null();
510 } // end switch
512 // append the vb to the pdu
513 pdu += tempvb;
516 return 0;
519 const unsigned char *wpdu::get_community() const
521 return community_name;