diff options
Diffstat (limited to 'ACE/ASNMP/asnmp/transaction.cpp')
-rw-r--r-- | ACE/ASNMP/asnmp/transaction.cpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/ACE/ASNMP/asnmp/transaction.cpp b/ACE/ASNMP/asnmp/transaction.cpp new file mode 100644 index 00000000000..2f29cf79544 --- /dev/null +++ b/ACE/ASNMP/asnmp/transaction.cpp @@ -0,0 +1,207 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// asnmp +// +// = FILENAME +// transaction.cpp +// +// = DESCRIPTION +// implements blocking SNMPv1 API using a simple state machine +// transactions over UDP/IP networks +// +// = AUTHOR +// Michael R MacFaden mrm@cisco.com - remove v2c, async, rework for ACE +// ============================================================================ + +#include "ace/Reactor.h" +#include "asnmp/transaction.h" +#include "ace/OS_NS_string.h" + +ACE_RCSID(asnmp, transaction, "$Id$") + +// pre: pdu, target report valid() == 1 +// post: pdu sent out over the wire +inline void reset_receive_buffer(iovec& io) +{ + io.iov_base = 0; + io.iov_len = 0; +} + +transaction::transaction(const Pdu& pdu, const UdpTarget& target, + ACE_SOCK_Dgram& io): + result_(0), + wp_(pdu,target), params_(target), session_(io) +{ + // last step, convert address (get ride of this once we have merged address + UdpAddress udp; + target.get_address(udp); + // via string conversion "dotted-quad:port" + ACE_INET_Addr tmp(udp); + addr_ = tmp; + reset_receive_buffer(receive_iovec_); +} + +transaction::~transaction() +{ + ACE_Reactor::instance()->remove_handler(this, READ_MASK | DONT_CALL); + ACE_Reactor::instance()->cancel_timer(this); + + delete [] (char *) receive_iovec_.iov_base; +} + +// implement state machine, send, wait (timeout/results) return +int transaction::run() +{ + int rc, done = 0; + int retry_counter = 0; + ACE_Time_Value to(params_.get_timeout(), 0); // seconds + ACE_Reactor *reactor = ACE_Reactor::instance (); + + // 1. register io port for read access + if (reactor->register_handler(session_.get_handle(), this, + ACE_Event_Handler::READ_MASK) == -1) + return SNMP_CLASS_INTERNAL_ERROR; + + // register a time handler and a socket with this + + while (!done) { + + if ((rc = send()) < 0) // send pkt to agent + return rc; + else { + if (retry_counter++ > params_.get_retry()) + return SNMP_CLASS_TIMEOUT; + } + + // 2. wait for events (timeout, returned msg) + if (( rc = reactor->handle_events (to)) == 1) // one handler registered + return 0; + else { + if (rc == 0) { + to.set(params_.get_timeout(), 0); + } + else + return SNMP_CLASS_INTERNAL_ERROR; + } + } + return SNMP_CLASS_INTERNAL_ERROR; +} + +// implement state machine, send, wait (timeout/results) return +int transaction::run(transaction_result * r) +{ + result_ = r; + int rc; + + // 1. register io port for read access + ACE_Reactor * reactor = ACE_Reactor::instance(); + if (reactor->register_handler(session_.get_handle(), + this, + READ_MASK) == -1) + return SNMP_CLASS_INTERNAL_ERROR; + + retry_counter_ = 0; + + // register a time handler and a socket with this + ACE_Time_Value to (params_.get_timeout()); + if (reactor->schedule_timer(this, 0, to, to) < 0) + return SNMP_CLASS_INTERNAL_ERROR; + + if ((rc = send()) < 0) // send pkt to agent + return rc; + return 0; +} + +// got back response from SNMPv1 agent - process it +int transaction::handle_input (ACE_HANDLE) +{ + // OS allocates iovec_.iov_base ptr and len + delete [] (char*) receive_iovec_.iov_base; + reset_receive_buffer(receive_iovec_); + int rc = session_.recv(&receive_iovec_, receive_addr_, 0); + if (rc == -1) + { + delete [] (char*) receive_iovec_.iov_base; + reset_receive_buffer(receive_iovec_); + if (result_) + result_->result(this, SNMP_CLASS_RESOURCE_UNAVAIL); + return SNMP_CLASS_RESOURCE_UNAVAIL; + } + if (result_) + result_->result(this, rc); + + return 0; +} + +int transaction::handle_timeout(const ACE_Time_Value &, + const void *) +{ + if (send() < 0) // send pkt to agent + result_->result(this, 0); + else + if (retry_counter_++ > params_.get_retry()) + result_->result(this, SNMP_CLASS_TIMEOUT); + + return 0; +} + + +const ACE_INET_Addr& transaction::get_from_addr() const +{ + return receive_addr_; +} + + +// return pdu to caller +int transaction::result(Pdu& pdu, char *comm_str, ACE_INET_Addr *from) +{ + // TODO: check to see the sender matches the receiver address.. + + // remove any vbs existing in this pdu + pdu.delete_all_vbs(); + + // any data to return? + if (receive_iovec_.iov_len == 0) + return -1; + + wpdu tmp(receive_iovec_); + + snmp_version ver; + + // return comm str and from address of incomming pdu if requested + int rc = tmp.get_pdu(pdu, ver); + if (comm_str) + ACE_OS::strcpy(comm_str, (char *)tmp.get_community()); + if (from) + *from = receive_addr_; + return rc; +} + +transaction::transaction(ACE_SOCK_Dgram& io) +: result_(0), session_(io) +{ + reset_receive_buffer(receive_iovec_); +} + + +int transaction::send() +{ + iovec io = wp_.get_buffer(); + if (io.iov_len == 0) { + // NO DATA ? + return -1; + } + ssize_t rc = session_.send (io.iov_base, io.iov_len, addr_ , 0); + return rc; +} + +transaction_result::~transaction_result() {} + +ACE_HANDLE +transaction::get_handle () const +{ + return session_.get_handle (); +} |