1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
/* -*-C++-*- */
// ============================================================================
//
// = 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"
// 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 [] receive_iovec_.iov_base;
}
// implement state machine, send, wait (timeout/results) return
int transaction::run()
{
int rc, done = FALSE;
int retry_counter = 0;
ACE_Time_Value to(params_.get_timeout(), 0); // seconds
ACE_Reactor reactor;
// 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 [] receive_iovec_.iov_base;
reset_receive_buffer(receive_iovec_);
int rc = session_.recv(&receive_iovec_, receive_addr_, 0);
if (rc == -1) {
delete [] 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;
}
return rc;
}
int transaction::handle_timeout(const ACE_Time_Value &,
const void *)
{
int rc;
if ((rc = 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() {}
|