6 * Portable Windows Library
8 * Copyright (c) 1993-2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
27 * Revision 1.9 2002/11/06 22:47:25 robertj
28 * Fixed header comment (copyright etc)
30 * Revision 1.8 1998/11/30 04:52:07 robertj
31 * New directory structure
33 * Revision 1.7 1998/10/13 14:06:34 robertj
34 * Complete rewrite of memory leak detection code.
36 * Revision 1.6 1998/09/23 06:22:40 robertj
37 * Added open source copyright license.
39 * Revision 1.5 1996/11/10 21:06:17 robertj
40 * Fixed endless retry bug in SNMP get.
42 * Revision 1.4 1996/11/04 04:00:00 robertj
43 * Added support for UDP packet truncation is reading SNMP reply.
45 * Revision 1.3 1996/10/08 13:06:24 robertj
46 * Fixed SNMP timeout (GNU compatibility).
48 * Revision 1.2 1996/09/20 12:20:19 robertj
49 * Used read timeout instead of member variable.
51 * Revision 1.1 1996/09/14 13:14:59 robertj
57 #include <ptclib/psnmp.h>
62 #define SNMP_VERSION 0
63 #define SNMP_PORT "snmp 161"
65 static const char defaultCommunity
[] = "public";
68 ///////////////////////////////////////////////////////////////
73 PSNMPClient::PSNMPClient(PINDEX retry
, PINDEX timeout
,
74 PINDEX rxSize
, PINDEX txSize
)
75 : community(defaultCommunity
),
76 version(SNMP_VERSION
),
81 SetReadTimeout(PTimeInterval(0, timeout
));
82 requestId
= rand() % 0x7fffffff;
86 PSNMPClient::PSNMPClient(const PString
& host
, PINDEX retry
,
87 PINDEX timeout
, PINDEX rxSize
, PINDEX txSize
)
89 community(defaultCommunity
),
90 version(SNMP_VERSION
),
95 SetReadTimeout(PTimeInterval(0, timeout
));
96 Open(new PUDPSocket(host
, SNMP_PORT
));
97 requestId
= rand() % 0x7fffffff;
101 void PSNMPClient::SetVersion(PASNInt newVersion
)
103 version
= newVersion
;
107 PASNInt
PSNMPClient::GetVersion() const
113 void PSNMPClient::SetCommunity(const PString
& str
)
119 PString
PSNMPClient::GetCommunity() const
125 void PSNMPClient::SetRequestID(PASNInt newRequestID
)
127 requestId
= newRequestID
;
131 PASNInt
PSNMPClient::GetRequestID() const
137 BOOL
PSNMPClient::WriteGetRequest(PSNMPVarBindingList
& varsIn
,
138 PSNMPVarBindingList
& varsOut
)
140 return WriteRequest(GetRequest
, varsIn
, varsOut
);
144 BOOL
PSNMPClient::WriteGetNextRequest(PSNMPVarBindingList
& varsIn
,
145 PSNMPVarBindingList
& varsOut
)
147 return WriteRequest(GetNextRequest
, varsIn
, varsOut
);
151 BOOL
PSNMPClient::WriteSetRequest(PSNMPVarBindingList
& varsIn
,
152 PSNMPVarBindingList
& varsOut
)
154 return WriteRequest(SetRequest
, varsIn
, varsOut
);
158 PSNMP::ErrorType
PSNMPClient::GetLastErrorCode() const
160 return lastErrorCode
;
164 PINDEX
PSNMPClient::GetLastErrorIndex() const
166 return lastErrorIndex
;
170 PString
PSNMPClient::GetLastErrorText() const
172 return PSNMP::GetErrorText(lastErrorCode
);
175 BOOL
PSNMPClient::ReadRequest(PBYTEArray
& readBuffer
)
177 readBuffer
.SetSize(maxRxSize
);
182 if (!Read(readBuffer
.GetPointer()+rxSize
, maxRxSize
- rxSize
)) {
184 // if the buffer was too small, then we are receiving datagrams
185 // and the datagram was too big
186 if (PChannel::GetErrorCode() == PChannel::BufferTooSmall
)
187 lastErrorCode
= RxBufferTooSmall
;
189 lastErrorCode
= NoResponse
;
192 } else if ((rxSize
+ GetLastReadCount()) >= 10)
196 rxSize
+= GetLastReadCount();
199 rxSize
+= GetLastReadCount();
203 // if not a valid sequence header, then stop reading
205 if ((readBuffer
[0] != 0x30) ||
206 !PASNObject::DecodeASNLength(readBuffer
, hdrLen
, len
)) {
207 lastErrorCode
= MalformedResponse
;
211 // length of packet is length of header + length of data
212 len
= (WORD
)(len
+ hdrLen
);
214 // return TRUE if we have the packet, else return FALSE
215 if (len
<= maxRxSize
)
218 lastErrorCode
= RxBufferTooSmall
;
222 // and get a new data ptr
224 readBuffer
.SetSize(len
);
226 // read the remainder of the packet
227 while (rxSize
< len
) {
228 if (!Read(readBuffer
.GetPointer()+rxSize
, len
- rxSize
)) {
229 lastErrorCode
= NoResponse
;
232 rxSize
+= GetLastReadCount();
238 BOOL
PSNMPClient::WriteRequest(PASNInt requestCode
,
239 PSNMPVarBindingList
& vars
,
240 PSNMPVarBindingList
& varsOut
)
243 PASNSequence
* pduData
= new PASNSequence((BYTE
)requestCode
);
244 PASNSequence
* bindingList
= new PASNSequence();
248 // build a get request PDU
249 pdu
.AppendInteger(version
);
250 pdu
.AppendString(community
);
253 // build the PDU data
254 PASNInt thisRequestId
= requestId
;
255 requestId
= rand() % 0x7fffffff;
256 pduData
->AppendInteger(thisRequestId
);
257 pduData
->AppendInteger(0); // error status
258 pduData
->AppendInteger(0); // error index
259 pduData
->Append(bindingList
); // binding list
261 // build the binding list
263 for (i
= 0; i
< vars
.GetSize(); i
++) {
264 PASNSequence
* binding
= new PASNSequence();
265 bindingList
->Append(binding
);
266 binding
->AppendObjectID(vars
.GetObjectID(i
));
267 binding
->Append((PASNObject
*)vars
[i
].Clone());
270 // encode the PDU into a buffer
271 PBYTEArray sendBuffer
;
272 pdu
.Encode(sendBuffer
);
274 if (sendBuffer
.GetSize() > maxTxSize
) {
275 lastErrorCode
= TxDataTooBig
;
281 PINDEX retry
= retryMax
;
286 if (!Write(sendBuffer
, sendBuffer
.GetSize())) {
287 lastErrorCode
= SendFailed
;
292 if (ReadRequest(readBuffer
))
294 else if ((lastErrorCode
!= NoResponse
) || (retry
== 0))
300 // parse the response
301 PASNSequence
response(readBuffer
);
302 PINDEX seqLen
= response
.GetSize();
306 response
[0].GetType() != PASNObject::Integer
||
307 response
[1].GetType() != PASNObject::String
||
308 response
[2].GetType() != PASNObject::Choice
) {
309 lastErrorCode
= MalformedResponse
;
313 // check the PDU data
314 const PASNSequence
& rPduData
= response
[2].GetSequence();
315 seqLen
= rPduData
.GetSize();
317 rPduData
.GetChoice() != GetResponse
||
318 rPduData
[0].GetType() != PASNObject::Integer
||
319 rPduData
[1].GetType() != PASNObject::Integer
||
320 rPduData
[2].GetType() != PASNObject::Integer
||
321 rPduData
[3].GetType() != PASNObject::Sequence
) {
322 lastErrorCode
= MalformedResponse
;
326 // check the request ID
327 PASNInt returnedRequestId
= rPduData
[0].GetInteger();
328 if (returnedRequestId
!= thisRequestId
) {
329 lastErrorCode
= MalformedResponse
;
333 // check the error status and return if non-zero
334 PASNInt errorStatus
= rPduData
[1].GetInteger();
335 if (errorStatus
!= 0) {
336 lastErrorIndex
= rPduData
[2].GetInteger();
337 lastErrorCode
= (ErrorType
)errorStatus
;
341 // check the variable bindings
342 const PASNSequence
& rBindings
= rPduData
[3].GetSequence();
343 PINDEX bindingCount
= rBindings
.GetSize();
345 // create the return list
346 for (i
= 0; i
< bindingCount
; i
++) {
347 if (rBindings
[i
].GetType() != PASNObject::Sequence
) {
348 lastErrorIndex
= i
+1;
349 lastErrorCode
= MalformedResponse
;
352 const PASNSequence
& rVar
= rBindings
[i
].GetSequence();
353 if (rVar
.GetSize() != 2 ||
354 rVar
[0].GetType() != PASNObject::ObjectID
) {
355 lastErrorIndex
= i
+1;
356 lastErrorCode
= MalformedResponse
;
359 varsOut
.Append(rVar
[0].GetString(), (PASNObject
*)rVar
[1].Clone());
362 lastErrorCode
= NoError
;
368 ///////////////////////////////////////////////////////////////
373 void PSNMP::SendEnterpriseTrap (
374 const PIPSocket::Address
& addr
,
375 const PString
& community
,
376 const PString
& enterprise
,
378 PASNUnsigned timeTicks
,
381 PSNMPVarBindingList vars
;
393 void PSNMP::SendEnterpriseTrap (
394 const PIPSocket::Address
& addr
,
395 const PString
& community
,
396 const PString
& enterprise
,
398 PASNUnsigned timeTicks
,
399 const PSNMPVarBindingList
& vars
,
413 void PSNMP::SendTrap(const PIPSocket::Address
& addr
,
414 PSNMP::TrapType trapType
,
415 const PString
& community
,
416 const PString
& enterprise
,
418 PASNUnsigned timeTicks
,
419 const PSNMPVarBindingList
& vars
,
422 PIPSocket::Address agentAddress
;
423 PIPSocket::GetHostAddress(agentAddress
);
436 void PSNMP::SendTrap(const PIPSocket::Address
& addr
,
437 PSNMP::TrapType trapType
,
438 const PString
& community
,
439 const PString
& enterprise
,
441 PASNUnsigned timeTicks
,
442 const PSNMPVarBindingList
& vars
,
443 const PIPSocket::Address
& agentAddress
,
447 // send the trap to specified remote host
448 PUDPSocket
socket(addr
, sendPort
);
450 WriteTrap(socket
, trapType
, community
, enterprise
,
451 specificTrap
, timeTicks
, vars
, agentAddress
);
454 void PSNMP::WriteTrap( PChannel
& channel
,
455 PSNMP::TrapType trapType
,
456 const PString
& community
,
457 const PString
& enterprise
,
459 PASNUnsigned timeTicks
,
460 const PSNMPVarBindingList
& vars
,
461 const PIPSocket::Address
& agentAddress
)
464 PASNSequence
* pduData
= new PASNSequence((BYTE
)Trap
);
465 PASNSequence
* bindingList
= new PASNSequence();
467 // build a trap PDU PDU
468 pdu
.AppendInteger(1);
469 pdu
.AppendString(community
);
472 // build the PDU data
473 pduData
->AppendObjectID(enterprise
); // enterprise
474 pduData
->Append(new PASNIPAddress(agentAddress
)); // agent address
475 pduData
->AppendInteger((int)trapType
); // trap type
476 pduData
->AppendInteger(specificTrap
); // specific trap
477 pduData
->Append(new PASNTimeTicks(timeTicks
)); // time of event
478 pduData
->Append(bindingList
); // binding list
480 // build the binding list
481 for (PINDEX i
= 0; i
< vars
.GetSize(); i
++) {
482 PASNSequence
* binding
= new PASNSequence();
483 bindingList
->Append(binding
);
484 binding
->AppendObjectID(vars
.GetObjectID(i
));
485 binding
->Append((PASNObject
*)vars
[i
].Clone());
488 // encode the PDU into a buffer
489 PBYTEArray sendBuffer
;
490 pdu
.Encode(sendBuffer
);
492 // send the trap to specified remote host
493 channel
.Write(sendBuffer
, sendBuffer
.GetSize());
497 // End Of File ///////////////////////////////////////////////////////////////