Merge pull request #2258 from likema/log-msg-reset-ostream
[ACE_TAO.git] / ACE / ASNMP / asnmp / transaction.cpp
blob9081593e4d86fdc2c4d07e1cac5c93a5fddb72e9
2 //=============================================================================
3 /**
4 * @file transaction.cpp
6 * implements blocking SNMPv1 API using a simple state machine
7 * transactions over UDP/IP networks
9 * @author Michael R MacFaden mrm@cisco.com - remove v2c
10 * @author async
11 * @author rework for ACE
13 //=============================================================================
16 #include "ace/Reactor.h"
17 #include "asnmp/transaction.h"
18 #include "ace/OS_NS_string.h"
20 // pre: pdu, target report valid() == 1
21 // post: pdu sent out over the wire
22 inline void reset_receive_buffer(iovec& io)
24 io.iov_base = 0;
25 io.iov_len = 0;
28 transaction::transaction(const Pdu& pdu, const UdpTarget& target,
29 ACE_SOCK_Dgram& io):
30 result_(0),
31 wp_(pdu,target), params_(target), session_(io)
33 // last step, convert address (get ride of this once we have merged address
34 UdpAddress udp;
35 target.get_address(udp);
36 // via string conversion "dotted-quad:port"
37 ACE_INET_Addr tmp(udp);
38 addr_ = tmp;
39 reset_receive_buffer(receive_iovec_);
42 transaction::~transaction()
44 ACE_Reactor::instance()->remove_handler(this, READ_MASK | DONT_CALL);
45 ACE_Reactor::instance()->cancel_timer(this);
47 delete [] (char *) receive_iovec_.iov_base;
50 // implement state machine, send, wait (timeout/results) return
51 int transaction::run()
53 int rc, done = 0;
54 int retry_counter = 0;
55 ACE_Time_Value to(params_.get_timeout(), 0); // seconds
56 ACE_Reactor *reactor = ACE_Reactor::instance ();
58 // 1. register io port for read access
59 if (reactor->register_handler(session_.get_handle(), this,
60 ACE_Event_Handler::READ_MASK) == -1)
61 return SNMP_CLASS_INTERNAL_ERROR;
63 // register a time handler and a socket with this
65 while (!done) {
66 if ((rc = this->send()) < 0) // send pkt to agent
67 return rc;
68 else {
69 if (retry_counter++ > params_.get_retry())
70 return SNMP_CLASS_TIMEOUT;
73 // 2. wait for events (timeout, returned msg)
74 if (( rc = reactor->handle_events (to)) == 1) // one handler registered
75 return 0;
76 else {
77 if (rc == 0) {
78 to.set(params_.get_timeout(), 0);
80 else
81 return SNMP_CLASS_INTERNAL_ERROR;
84 return SNMP_CLASS_INTERNAL_ERROR;
87 // implement state machine, send, wait (timeout/results) return
88 int transaction::run(transaction_result * r)
90 result_ = r;
91 int rc;
93 // 1. register io port for read access
94 ACE_Reactor * reactor = ACE_Reactor::instance();
95 if (reactor->register_handler(session_.get_handle(),
96 this,
97 READ_MASK) == -1)
98 return SNMP_CLASS_INTERNAL_ERROR;
100 retry_counter_ = 0;
102 // register a time handler and a socket with this
103 ACE_Time_Value to (params_.get_timeout());
104 if (reactor->schedule_timer(this, 0, to, to) == -1)
105 return SNMP_CLASS_INTERNAL_ERROR;
107 if ((rc = this->send()) < 0) // send pkt to agent
108 return rc;
109 return 0;
112 // got back response from SNMPv1 agent - process it
113 int transaction::handle_input (ACE_HANDLE)
115 // OS allocates iovec_.iov_base ptr and len
116 delete [] (char*) receive_iovec_.iov_base;
117 reset_receive_buffer(receive_iovec_);
118 int rc = session_.recv(&receive_iovec_, receive_addr_, 0);
119 if (rc == -1)
121 delete [] (char*) receive_iovec_.iov_base;
122 reset_receive_buffer(receive_iovec_);
123 if (result_)
124 result_->result(this, SNMP_CLASS_RESOURCE_UNAVAIL);
125 return SNMP_CLASS_RESOURCE_UNAVAIL;
127 if (result_)
128 result_->result(this, rc);
130 return 0;
133 int transaction::handle_timeout(const ACE_Time_Value &,
134 const void *)
136 if (this->send() < 0) // send pkt to agent
137 result_->result(this, 0);
138 else
139 if (retry_counter_++ > params_.get_retry())
140 result_->result(this, SNMP_CLASS_TIMEOUT);
142 return 0;
146 const ACE_INET_Addr& transaction::get_from_addr() const
148 return receive_addr_;
152 // return pdu to caller
153 int transaction::result(Pdu& pdu, char *comm_str, ACE_INET_Addr *from)
155 // TODO: check to see the sender matches the receiver address..
157 // remove any vbs existing in this pdu
158 pdu.delete_all_vbs();
160 // any data to return?
161 if (receive_iovec_.iov_len == 0)
162 return -1;
164 wpdu tmp(receive_iovec_);
166 snmp_version ver;
168 // return comm str and from address of incomming pdu if requested
169 int rc = tmp.get_pdu(pdu, ver);
170 if (comm_str)
171 ACE_OS::strcpy(comm_str, (char *)tmp.get_community());
172 if (from)
173 *from = receive_addr_;
174 return rc;
177 transaction::transaction(ACE_SOCK_Dgram& io)
178 : result_(0), session_(io)
180 reset_receive_buffer(receive_iovec_);
184 int transaction::send()
186 iovec io = wp_.get_buffer();
187 if (io.iov_len == 0) {
188 // NO DATA ?
189 return -1;
191 ssize_t rc = session_.send (io.iov_base, io.iov_len, addr_ , 0);
192 return rc;
195 transaction_result::~transaction_result() {}
197 ACE_HANDLE
198 transaction::get_handle () const
200 return session_.get_handle ();