2 //=============================================================================
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
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
)
28 transaction::transaction(const Pdu
& pdu
, const UdpTarget
& target
,
31 wp_(pdu
,target
), params_(target
), session_(io
)
33 // last step, convert address (get ride of this once we have merged address
35 target
.get_address(udp
);
36 // via string conversion "dotted-quad:port"
37 ACE_INET_Addr
tmp(udp
);
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()
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
66 if ((rc
= this->send()) < 0) // send pkt to agent
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
78 to
.set(params_
.get_timeout(), 0);
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
)
93 // 1. register io port for read access
94 ACE_Reactor
* reactor
= ACE_Reactor::instance();
95 if (reactor
->register_handler(session_
.get_handle(),
98 return SNMP_CLASS_INTERNAL_ERROR
;
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
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);
121 delete [] (char*) receive_iovec_
.iov_base
;
122 reset_receive_buffer(receive_iovec_
);
124 result_
->result(this, SNMP_CLASS_RESOURCE_UNAVAIL
);
125 return SNMP_CLASS_RESOURCE_UNAVAIL
;
128 result_
->result(this, rc
);
133 int transaction::handle_timeout(const ACE_Time_Value
&,
136 if (this->send() < 0) // send pkt to agent
137 result_
->result(this, 0);
139 if (retry_counter_
++ > params_
.get_retry())
140 result_
->result(this, SNMP_CLASS_TIMEOUT
);
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)
164 wpdu
tmp(receive_iovec_
);
168 // return comm str and from address of incomming pdu if requested
169 int rc
= tmp
.get_pdu(pdu
, ver
);
171 ACE_OS::strcpy(comm_str
, (char *)tmp
.get_community());
173 *from
= receive_addr_
;
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) {
191 ssize_t rc
= session_
.send (io
.iov_base
, io
.iov_len
, addr_
, 0);
195 transaction_result::~transaction_result() {}
198 transaction::get_handle () const
200 return session_
.get_handle ();