snmpclnt.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:14k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * snmpclnt.cxx
  3.  *
  4.  * SNMP Client class
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  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/
  14.  *
  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
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: snmpclnt.cxx,v $
  30.  * Revision 1.8  1998/11/30 04:52:07  robertj
  31.  * New directory structure
  32.  *
  33.  * Revision 1.7  1998/10/13 14:06:34  robertj
  34.  * Complete rewrite of memory leak detection code.
  35.  *
  36.  * Revision 1.6  1998/09/23 06:22:40  robertj
  37.  * Added open source copyright license.
  38.  *
  39.  * Revision 1.5  1996/11/10 21:06:17  robertj
  40.  * Fixed endless retry bug in SNMP get.
  41.  *
  42.  * Revision 1.4  1996/11/04 04:00:00  robertj
  43.  * Added support for UDP packet truncation is reading SNMP reply.
  44.  *
  45.  * Revision 1.3  1996/10/08 13:06:24  robertj
  46.  * Fixed SNMP timeout (GNU compatibility).
  47.  *
  48.  * Revision 1.2  1996/09/20 12:20:19  robertj
  49.  * Used read timeout instead of member variable.
  50.  *
  51.  * Revision 1.1  1996/09/14 13:14:59  robertj
  52.  * Initial revision
  53.  *
  54.  */
  55. #include <ptlib.h>
  56. #include <ptclib/psnmp.h>
  57. #define new PNEW
  58. #define SNMP_VERSION 0
  59. #define SNMP_PORT "snmp 161"
  60. static const char defaultCommunity[] = "public";
  61. ///////////////////////////////////////////////////////////////
  62. //
  63. //  PSNMPClient
  64. //
  65. PSNMPClient::PSNMPClient(PINDEX retry, PINDEX timeout,
  66.                          PINDEX rxSize, PINDEX txSize)
  67.  : community(defaultCommunity),
  68.    version(SNMP_VERSION),
  69.    retryMax(retry),
  70.    maxRxSize(rxSize),
  71.    maxTxSize(txSize)
  72. {
  73.   SetReadTimeout(PTimeInterval(0, timeout));
  74.   requestId = rand() % 0x7fffffff;
  75. }
  76. PSNMPClient::PSNMPClient(const PString & host, PINDEX retry,
  77.                          PINDEX timeout, PINDEX rxSize, PINDEX txSize)
  78.  : hostName(host),
  79.    community(defaultCommunity),
  80.    version(SNMP_VERSION),
  81.    retryMax(retry),
  82.    maxRxSize(rxSize),
  83.    maxTxSize(txSize)
  84. {
  85.   SetReadTimeout(PTimeInterval(0, timeout));
  86.   Open(new PUDPSocket(host, SNMP_PORT));
  87.   requestId = rand() % 0x7fffffff;
  88. }
  89. void PSNMPClient::SetVersion(PASNInt newVersion)
  90. {
  91.   version = newVersion;
  92. }
  93. PASNInt PSNMPClient::GetVersion() const
  94. {
  95.   return version;
  96. }
  97. void PSNMPClient::SetCommunity(const PString & str)
  98. {
  99.   community = str;
  100. }
  101. PString PSNMPClient::GetCommunity() const
  102. {
  103.   return community;
  104. }
  105. void PSNMPClient::SetRequestID(PASNInt newRequestID)
  106. {
  107.   requestId = newRequestID;
  108. }
  109. PASNInt PSNMPClient::GetRequestID() const
  110. {
  111.   return requestId;
  112. }
  113. BOOL PSNMPClient::WriteGetRequest(PSNMPVarBindingList & varsIn,
  114.                                   PSNMPVarBindingList & varsOut)
  115. {
  116.   return WriteRequest(GetRequest, varsIn, varsOut);
  117. }
  118. BOOL PSNMPClient::WriteGetNextRequest(PSNMPVarBindingList & varsIn,
  119.                                       PSNMPVarBindingList & varsOut)
  120. {
  121.   return WriteRequest(GetNextRequest, varsIn, varsOut);
  122. }
  123. BOOL PSNMPClient::WriteSetRequest(PSNMPVarBindingList & varsIn,
  124.                                   PSNMPVarBindingList & varsOut)
  125. {
  126.   return WriteRequest(SetRequest, varsIn, varsOut);
  127. }
  128. PSNMP::ErrorType PSNMPClient::GetLastErrorCode() const
  129. {
  130.   return lastErrorCode;
  131. }
  132. PINDEX PSNMPClient::GetLastErrorIndex() const
  133. {
  134.   return lastErrorIndex;
  135. }
  136. PString PSNMPClient::GetLastErrorText() const
  137. {
  138.   return PSNMP::GetErrorText(lastErrorCode);
  139. }
  140. BOOL PSNMPClient::ReadRequest(PBYTEArray & readBuffer)
  141. {
  142.   readBuffer.SetSize(maxRxSize);
  143.   PINDEX rxSize = 0;
  144.   for (;;) {
  145.     if (!Read(readBuffer.GetPointer()+rxSize, maxRxSize - rxSize)) {
  146.       // if the buffer was too small, then we are receiving datagrams
  147.       // and the datagram was too big
  148.       if (PChannel::GetErrorCode() == PChannel::BufferTooSmall) 
  149.         lastErrorCode = RxBufferTooSmall;
  150.       else
  151.         lastErrorCode = NoResponse;
  152.       return FALSE;
  153.     } else if ((rxSize + GetLastReadCount()) >= 10)
  154.       break;
  155.     else 
  156.       rxSize += GetLastReadCount();
  157.   }
  158.   rxSize += GetLastReadCount();
  159.   PINDEX hdrLen = 1;
  160.   // if not a valid sequence header, then stop reading
  161.   WORD len;
  162.   if ((readBuffer[0] != 0x30) ||
  163.       !PASNObject::DecodeASNLength(readBuffer, hdrLen, len)) {
  164.     lastErrorCode = MalformedResponse;
  165.     return FALSE;
  166.   }
  167.   // length of packet is length of header + length of data
  168.   len = (WORD)(len + hdrLen);
  169.   // return TRUE if we have the packet, else return FALSE
  170.   if (len <= maxRxSize) 
  171.     return TRUE;
  172.   lastErrorCode = RxBufferTooSmall;
  173.   return FALSE;
  174. #if 0
  175.   // and get a new data ptr
  176.   if (maxRxSize < len) 
  177.     readBuffer.SetSize(len);
  178.   // read the remainder of the packet
  179.   while (rxSize < len) {
  180.     if (!Read(readBuffer.GetPointer()+rxSize, len - rxSize)) {
  181.       lastErrorCode = NoResponse;
  182.       return FALSE;
  183.     }
  184.     rxSize += GetLastReadCount();
  185.   }
  186.   return TRUE;
  187. #endif
  188. }
  189. BOOL PSNMPClient::WriteRequest(PASNInt requestCode,
  190.                                PSNMPVarBindingList & vars,
  191.                                PSNMPVarBindingList & varsOut)
  192. {
  193.   PASNSequence pdu;
  194.   PASNSequence * pduData     = new PASNSequence((BYTE)requestCode);
  195.   PASNSequence * bindingList = new PASNSequence();
  196.   lastErrorIndex = 0;
  197.   // build a get request PDU
  198.   pdu.AppendInteger(version);
  199.   pdu.AppendString(community);
  200.   pdu.Append(pduData);
  201.   // build the PDU data
  202.   PASNInt thisRequestId = requestId;
  203.   requestId = rand() % 0x7fffffff;
  204.   pduData->AppendInteger(thisRequestId);
  205.   pduData->AppendInteger(0);           // error status
  206.   pduData->AppendInteger(0);           // error index
  207.   pduData->Append(bindingList);        // binding list
  208.   // build the binding list
  209.   PINDEX i;
  210.   for (i = 0; i < vars.GetSize(); i++) {
  211.     PASNSequence * binding = new PASNSequence();
  212.     bindingList->Append(binding);
  213.     binding->AppendObjectID(vars.GetObjectID(i));
  214.     binding->Append((PASNObject *)vars[i].Clone());
  215.   }
  216.   // encode the PDU into a buffer
  217.   PBYTEArray sendBuffer;
  218.   pdu.Encode(sendBuffer);
  219.   if (sendBuffer.GetSize() > maxTxSize) {
  220.     lastErrorCode = TxDataTooBig;
  221.     return FALSE;
  222.   }
  223.   varsOut.RemoveAll();
  224.   PINDEX retry = retryMax;
  225.   for (;;) {
  226.     // send the packet
  227.     if (!Write(sendBuffer, sendBuffer.GetSize())) {
  228.       lastErrorCode = SendFailed;
  229.       return FALSE;
  230.     }
  231.     // receive a packet
  232.     if (ReadRequest(readBuffer))
  233.       break;
  234.     else if ((lastErrorCode != NoResponse) || (retry == 0))
  235.       return FALSE;
  236.     else
  237.       retry--;
  238.   }
  239.   // parse the response
  240.   PASNSequence response(readBuffer);
  241.   PINDEX seqLen = response.GetSize();
  242.   // check PDU
  243.   if (seqLen != 3 ||
  244.       response[0].GetType() != PASNObject::Integer ||
  245.       response[1].GetType() != PASNObject::String ||
  246.       response[2].GetType() != PASNObject::Choice) {
  247.     lastErrorCode = MalformedResponse;
  248.     return FALSE;
  249.   }
  250.   // check the PDU data
  251.   const PASNSequence & rPduData = response[2].GetSequence();
  252.   seqLen = rPduData.GetSize();
  253.   if (seqLen != 4 ||
  254.       rPduData.GetChoice()  != GetResponse ||
  255.       rPduData[0].GetType() != PASNObject::Integer ||
  256.       rPduData[1].GetType() != PASNObject::Integer ||
  257.       rPduData[2].GetType() != PASNObject::Integer ||
  258.       rPduData[3].GetType() != PASNObject::Sequence) {
  259.     lastErrorCode = MalformedResponse;
  260.     return FALSE;
  261.   }
  262.   // check the request ID
  263.   PASNInt returnedRequestId = rPduData[0].GetInteger();
  264.   if (returnedRequestId != thisRequestId) {
  265.     lastErrorCode = MalformedResponse;
  266.     return FALSE;
  267.   }
  268.   
  269.   // check the error status and return if non-zero
  270.   PASNInt errorStatus = rPduData[1].GetInteger();
  271.   if (errorStatus != 0) {
  272.     lastErrorIndex = rPduData[2].GetInteger(); 
  273.     lastErrorCode = (ErrorType)errorStatus;
  274.     return FALSE;
  275.   }
  276.   // check the variable bindings
  277.   const PASNSequence & rBindings = rPduData[3].GetSequence();
  278.   PINDEX bindingCount = rBindings.GetSize();
  279.   // create the return list
  280.   for (i = 0; i < bindingCount; i++) {
  281.     if (rBindings[i].GetType() != PASNObject::Sequence) {
  282.       lastErrorIndex = i+1;
  283.       lastErrorCode  = MalformedResponse;
  284.       return FALSE;
  285.     }
  286.     const PASNSequence & rVar = rBindings[i].GetSequence();
  287.     if (rVar.GetSize() != 2 ||
  288.         rVar[0].GetType() != PASNObject::ObjectID) {
  289.       lastErrorIndex = i+1;
  290.       lastErrorCode = MalformedResponse;
  291.       return FALSE;
  292.     }
  293.     varsOut.Append(rVar[0].GetString(), (PASNObject *)rVar[1].Clone());
  294.   }
  295.   lastErrorCode = NoError;
  296.   return TRUE;
  297. }
  298. ///////////////////////////////////////////////////////////////
  299. //
  300. //  Trap routines
  301. //
  302. void PSNMP::SendEnterpriseTrap (
  303.                  const PIPSocket::Address & addr,
  304.                             const PString & community,
  305.                             const PString & enterprise,
  306.                                      PINDEX specificTrap,
  307.                                PASNUnsigned timeTicks,
  308.                                        WORD sendPort)
  309. {
  310.   PSNMPVarBindingList vars;
  311.   SendTrap(addr,
  312.            EnterpriseSpecific,
  313.            community,
  314.            enterprise,
  315.            specificTrap,
  316.            timeTicks,
  317.            vars,
  318.            sendPort);
  319. }
  320. void PSNMP::SendEnterpriseTrap (
  321.                  const PIPSocket::Address & addr,
  322.                             const PString & community,
  323.                             const PString & enterprise,
  324.                                      PINDEX specificTrap,
  325.                                PASNUnsigned timeTicks,
  326.                 const PSNMPVarBindingList & vars,
  327.                                        WORD sendPort)
  328. {
  329.   SendTrap(addr,
  330.            EnterpriseSpecific,
  331.            community,
  332.            enterprise,
  333.            specificTrap,
  334.            timeTicks,
  335.            vars,
  336.            sendPort);
  337. }
  338. void PSNMP::SendTrap(const PIPSocket::Address & addr,
  339.                                 PSNMP::TrapType trapType,
  340.                                 const PString & community,
  341.                                 const PString & enterprise,
  342.                                          PINDEX specificTrap,
  343.                                    PASNUnsigned timeTicks,
  344.                     const PSNMPVarBindingList & vars,
  345.                                            WORD sendPort)
  346. {
  347.   PIPSocket::Address agentAddress;
  348.   PIPSocket::GetHostAddress(agentAddress);
  349.   SendTrap(addr,
  350.            trapType,
  351.            community,
  352.            enterprise,
  353.            specificTrap,
  354.            timeTicks,
  355.            vars,
  356.            agentAddress,
  357.            sendPort);
  358. }
  359.                             
  360. void PSNMP::SendTrap(const PIPSocket::Address & addr,
  361.                                 PSNMP::TrapType trapType,
  362.                                 const PString & community,
  363.                                 const PString & enterprise,
  364.                                          PINDEX specificTrap,
  365.                                    PASNUnsigned timeTicks,
  366.                     const PSNMPVarBindingList & vars,
  367.                      const PIPSocket::Address & agentAddress,
  368.                                            WORD sendPort)
  369.                             
  370. {
  371.   // send the trap to specified remote host
  372.   PUDPSocket socket(addr, sendPort);
  373.   if (socket.IsOpen())
  374.     WriteTrap(socket, trapType, community, enterprise,
  375.               specificTrap, timeTicks, vars, agentAddress);
  376. }
  377. void PSNMP::WriteTrap(                 PChannel & channel,
  378.                                   PSNMP::TrapType trapType,
  379.                                   const PString & community,
  380.                                   const PString & enterprise,
  381.                                            PINDEX specificTrap,
  382.                                      PASNUnsigned timeTicks,
  383.                       const PSNMPVarBindingList & vars,
  384.                        const PIPSocket::Address & agentAddress)
  385. {
  386.   PASNSequence pdu;
  387.   PASNSequence * pduData     = new PASNSequence((BYTE)Trap);
  388.   PASNSequence * bindingList = new PASNSequence();
  389.   // build a trap PDU PDU
  390.   pdu.AppendInteger(1);
  391.   pdu.AppendString(community);
  392.   pdu.Append(pduData);
  393.   // build the PDU data
  394.   pduData->AppendObjectID(enterprise);               // enterprise
  395.   pduData->Append(new PASNIPAddress(agentAddress)); // agent address
  396.   pduData->AppendInteger((int)trapType);             // trap type
  397.   pduData->AppendInteger(specificTrap);              // specific trap
  398.   pduData->Append(new PASNTimeTicks(timeTicks));    // time of event
  399.   pduData->Append(bindingList);                      // binding list
  400.   // build the binding list
  401.   for (PINDEX i = 0; i < vars.GetSize(); i++) {
  402.     PASNSequence * binding = new PASNSequence();
  403.     bindingList->Append(binding);
  404.     binding->AppendObjectID(vars.GetObjectID(i));
  405.     binding->Append((PASNObject *)vars[i].Clone());
  406.   }
  407.   // encode the PDU into a buffer
  408.   PBYTEArray sendBuffer;
  409.   pdu.Encode(sendBuffer);
  410.   // send the trap to specified remote host
  411.   channel.Write(sendBuffer, sendBuffer.GetSize());
  412. }
  413. // End Of File ///////////////////////////////////////////////////////////////