// $Id$ // ============================================================================ // // = LIBRARY // asnmp // // = FILENAME // pdu.cpp // // = DESCRIPTION // Pdu class implementation. Encapsulation of an SMI Protocol // Data Unit (PDU) in C++. // // = AUTHOR // Peter E Mellquist // Michael R MacFaden mrm@cisco.com - rework & ACE port // ============================================================================ /*=================================================================== Copyright (c) 1996 Hewlett-Packard Company ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS. Permission to use, copy, modify, distribute and/or sell this software and/or its documentation is hereby granted without fee. User agrees to display the above copyright notice and this license notice in all copies of the software and any documentation of the software. User agrees to assume all liability for the use of the software; Hewlett-Packard makes no representations about the suitability of this software for any purpose. It is provided "AS-IS without warranty of any kind,either express or implied. User hereby grants a royalty-free license to any and all derivatives based upon this software code base. =====================================================================*/ #include "asnmp/snmp.h" #include "asnmp/pdu.h" // include Pdu class definition ACE_RCSID(asnmp, pdu, "$Id$") //=====================[ constructor no args ]========================= Pdu::Pdu( void): vb_count_(0), error_status_(0), error_index_(0), validity_(0), request_id_(0), pdu_type_(0), notify_timestamp_(0), output_(0) { } //=====================[ constructor with vbs_ and count ]============== Pdu::Pdu( Vb* pvbs, const int pvb_count): vb_count_(0), error_index_(0), validity_(0), request_id_(0), pdu_type_(0), notify_timestamp_(0), output_(0) { int z; // looping variable // zero is ok if ( pvb_count == 0) { validity_ = 1; return; } // check for over then max if ( pvb_count > MAX_VBS) { validity_ = 0; return; } // loop through and assign internal vbs_ for (z = 0;z < pvb_count; z++) { validity_ = 0; ACE_NEW(vbs_[z], Vb( pvbs[z])); validity_ = 1; } // assign the vb count vb_count_ = pvb_count; validity_ = 1; } //=====================[ constructor with another Pdu instance ]======== Pdu::Pdu( const Pdu &pdu): vb_count_(0), error_index_(0), validity_(0), request_id_(0), pdu_type_(0), notify_timestamp_(0), output_(0) { *this = pdu; return; } //=====================[ destructor ]==================================== Pdu::~Pdu() { delete_all_vbs(); delete [] output_; } //=====================[ assignment to another Pdu object overloaded ]=== Pdu& Pdu::operator=( const Pdu &pdu) { int z; // looping variable // Initialize all mv's error_status_ = pdu.error_status_; error_index_ = pdu.error_index_; request_id_ = pdu.request_id_; pdu_type_ = pdu.pdu_type_; notify_id_ = pdu.notify_id_; notify_timestamp_ = pdu.notify_timestamp_; notify_enterprise_ = pdu.notify_enterprise_; validity_ = 1; // free up old vbs_ for ( z = 0;z < vb_count_; z++) delete vbs_[z]; vb_count_ = 0; // check for zero case if ( pdu.vb_count_ == 0) { return *this; } // loop through and fill em up for (z = 0; z < pdu.vb_count_; z++) { validity_ = 0; ACE_NEW_RETURN(vbs_[z], Vb ( *(pdu.vbs_[z])), *this); validity_ = 1; } vb_count_ = pdu.vb_count_; return *this; } // append operator, appends a string Pdu& Pdu::operator+=( Vb &vb) { // do we have room? if ( vb_count_ + 1 > MAX_VBS) return *this; // add the new one validity_ = 0; ACE_NEW_RETURN(vbs_[vb_count_], Vb (vb), *this); // set up validity_ validity_ = 1; // up the vb count vb_count_++; // return self reference return *this; } // return fomatted version of this object char * Pdu::to_string() { // determine how big a buffer and allocate it const int HEADER_STR = 100; unsigned size = HEADER_STR; // header takes up this much room int z; for ( z = 0; z < vb_count_; z++) size += ACE_OS::strlen(vbs_[z]->to_string()); ACE_NEW_RETURN(output_, char[size], ""); // print pdu header info sprintf(output_, "pdu: valid: %d type:%d, req:%d, cnt: %d, err stat: %d \ err idx: %d\n", validity_, pdu_type_, (int) request_id_, vb_count_, error_status_, error_index_ ); // now append vb pairs in this object for ( z = 0; z < vb_count_; z++) { ACE_OS::strcat(output_, vbs_[z]->to_string()); ACE_OS::strcat(output_, "\n\t"); } return output_; } //=====================[ extract Vbs from Pdu ]========================== // how do you know that the caler has enough memory??? // should I self allocate this in here and require the // caller then to free it up at soem later time int Pdu::get_vblist( Vb* pvbs, const int pvb_count) { if ((!pvbs) || ( pvb_count < 0) || ( pvb_count > vb_count_)) return 0; // loop through all vbs_ and assign to params int z; for (z = 0; z < pvb_count; z++) pvbs[z] = *vbs_[z]; return 1; } //=====================[ deposit Vbs ]=================================== int Pdu::set_vblist( Vb* pvbs, const int pvb_count) { // if invalid then don't destroy if ((!pvbs) || ( pvb_count < 0) || ( pvb_count > MAX_VBS)) return 0; // free up current vbs_ int z; for ( z = 0; z < vb_count_; z++) delete vbs_[z]; vb_count_ = 0; // check for zero case if ( pvb_count == 0) { validity_ = 1; error_status_ = 0; error_index_ = 0; request_id_ = 0; return 0; } // loop through all vbs_ and reassign them for ( z = 0; z < pvb_count; z++) { validity_ = 0; ACE_NEW_RETURN(vbs_[z], Vb (pvbs[z]), 0); validity_ = 1; } vb_count_ = pvb_count; // clear error status and index since no longer valid // request id may still apply so don't reassign it error_status_ = 0; error_index_ = 0; validity_ = 1; return 1; } //===================[ get a particular vb ]============================= // here the caller has already instantiated a vb object // index is zero based int Pdu::get_vb( Vb &vb, const int index) const { // can't have an index less than 0 if ( index < 0) return 0; // can't ask for something not there if ( index > (vb_count_ - 1)) return 0; // asssign it vb = *vbs_[index]; return 1; } //===================[ set a particular vb ]============================= int Pdu::set_vb( Vb &vb, const int index) { // can't set a vb at index less than 0 if ( index < 0) return 0; // can't ask for something not there if ( index > (vb_count_ - 1)) return 0; // delete what is there delete vbs_[index]; // assign it validity_ = 0; ACE_NEW_RETURN(vbs_[index], Vb (vb), 0); validity_ = 1; return 1; } //=====================[ return number of vbs_ ]========================== int Pdu::get_vb_count() const { return vb_count_; } //=====================[ return the error status ]======================= int Pdu::get_error_status() const { return error_status_; } char *Pdu::agent_error_reason() { int pdu_err = get_error_status(); if (pdu_err == 0) // any real error? return "not in error state"; int n_vbs = get_vb_count(); Vb bad; get_vb(bad, get_error_index() -1); // not zero based?? char *pmsg = Snmp::error_string(get_error_status()); char *id = bad.to_string_oid(); char *val = bad.to_string_value(); const int HDR_SZ = 100; if (!output_) { int size = ACE_OS::strlen(pmsg) + ACE_OS::strlen(id) + ACE_OS::strlen(val); ACE_NEW_RETURN(output_, char[size + HDR_SZ], ""); } ACE_OS::sprintf(output_, "FAIL PDU REPORT: pdu id: %d vb cnt: %d vb idx: %d \n\ msg: %s vb oid: %s value: %s", get_request_id(), n_vbs, get_error_index(), pmsg, id, val); return output_; } //=====================[ set the error status ]========================== // friend void set_error_status( Pdu *pdu, const int status) { if (pdu) pdu->error_status_ = status; } //=====================[ return the error index ]======================== int Pdu::get_error_index() const { return error_index_; } //=====================[ set the error index ]=========================== // friend void set_error_index( Pdu *pdu, const int index) { if (pdu) pdu->error_index_ = index; } //=====================[ clear error status ]============================= void clear_error_status( Pdu *pdu) { if (pdu) pdu->error_status_ = 0; } //=====================[ clear error index ]============================== void clear_error_index( Pdu *pdu) { if (pdu) pdu->error_index_ = 0; } //=====================[ return the request id ]========================== unsigned long Pdu::get_request_id() const { return request_id_; } //=====================[ set the request id ]============================= // friend function void set_request_id( Pdu *pdu, const unsigned long rid) { if (pdu) pdu->request_id_ = rid; } //=====================[ returns validity_ of Pdu instance ]=============== int Pdu::valid() const { return validity_; } //=====================[ get the pdu type ]=============================== unsigned short Pdu::get_type()const { return pdu_type_; } // set the pdu type void Pdu::set_type( unsigned short type) { pdu_type_ = type; } // trim off the last vb int Pdu::trim(const int p) { int lp = p; // verify that lp is legal if ( lp < 0 || lp > vb_count_) return 0; while ( lp != 0) { if ( vb_count_ > 0) { delete vbs_[vb_count_ - 1]; vb_count_--; } lp--; } return 1; } // delete a Vb anywhere within the Pdu int Pdu::delete_vb( const int p) { // position has to be in range if (( p < 0) || ( p > (vb_count_ - 1))) return 0; // safe to remove it delete vbs_[ p]; for ( int z=p;z < (vb_count_-1);z++) { vbs_[z] = vbs_[z+1]; } vb_count_--; return 1; } void Pdu::delete_all_vbs() { for ( int z = 0; z < vb_count_; z++) delete vbs_[z]; vb_count_ = 0; } // set notify timestamp void Pdu::set_notify_timestamp( const TimeTicks & timestamp) { notify_timestamp_ = timestamp; } // get notify timestamp void Pdu::get_notify_timestamp( TimeTicks & timestamp) const { timestamp = notify_timestamp_; } // set the notify id void Pdu::set_notify_id( const Oid id) { notify_id_ = id; } // get the notify id void Pdu::get_notify_id( Oid &id) const { id = notify_id_; } // set the notify enterprise void Pdu::set_notify_enterprise( const Oid &enterprise) { notify_enterprise_ = enterprise; } // get the notify enterprise void Pdu::get_notify_enterprise( Oid & enterprise) const { enterprise = notify_enterprise_; } // ------ class VbIter ------------------- VbIter::VbIter(Pdu& pdu): idx_(-1), pdu_(&pdu) { } // returns 1 if ok, else 0 if none left int VbIter::next(Vb& vb) { if (idx_ == -1) { idx_ = 0; pdu_->get_vb(vb, idx_++); return 1; } else if (idx_ < pdu_->get_vb_count()) { pdu_->get_vb(vb, idx_++); return 1; } return 0; // non left }