//*************************************************************************** // // File: // // Module: MS SNMP Provider // // Purpose: // // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved // //*************************************************************************** #include "precomp.h" #include #include #include #include #include #include #include #include #if _MSC_VER >= 1100 template<> UINT AFXAPI HashKey (SnmpObjectIdentifierType &key) #else UINT HashKey (SnmpObjectIdentifierType &key) #endif { SnmpObjectIdentifier *objectIdentifier = ( SnmpObjectIdentifier * ) key.GetValueEncoding () ; UCHAR *value = ( UCHAR * ) objectIdentifier->GetValue () ; ULONG length = objectIdentifier->GetValueLength () * sizeof ( ULONG ) ; #if 1 ULONG t_Length = length >> 2 ; value += t_Length ; length = length - t_Length ; #endif UINT hash; if (length > 1) { USHORT even = 0; USHORT odd = 0; #if 0 for (ULONG i = length >> 1; i--;) { even += *value++; odd += *value++; } if (length & 1) { even += *value; } #else for (ULONG i = length >> 2; i--;) { even += *value++; even += *value++; even += *value++; odd += *value++; } if (length & 1) { even += *value; } #endif hash = odd>>8; hash |= (odd & 0xff) << 8; hash ^= even; } else { hash = *value; } return hash ; } #if _MSC_VER >= 1100 template<> BOOL AFXAPI CompareElements ( const SnmpObjectIdentifierType* pElement1, const SnmpObjectIdentifierType* pElement2 ) #else BOOL CompareElements ( SnmpObjectIdentifierType* pElement1, SnmpObjectIdentifierType* pElement2 ) #endif { return *( ( SnmpObjectIdentifier * ) pElement1->GetValueEncoding () ) == *( ( SnmpObjectIdentifier * )pElement2->GetValueEncoding () ) ; } VarBindObject :: VarBindObject ( const SnmpObjectIdentifier &replyArg , const SnmpValue &valueArg ) : value ( NULL ) , reply ( replyArg ) { value = valueArg.Copy () ; } VarBindObject :: ~VarBindObject () { delete value ; } SnmpObjectIdentifier &VarBindObject :: GetObjectIdentifier () { return reply ; } SnmpValue &VarBindObject :: GetValue () { return *value ; } VarBindQueue :: VarBindQueue () { } VarBindQueue :: ~VarBindQueue () { POSITION position = queue.GetHeadPosition () ; while ( position ) { VarBindObject *varBindObject = queue.GetNext ( position ) ; delete varBindObject ; } queue.RemoveAll () ; } void VarBindQueue :: Add ( VarBindObject *varBindObject ) { queue.AddTail ( varBindObject ) ; } VarBindObject *VarBindQueue :: Get () { return queue.IsEmpty () ? NULL : queue.GetHead () ; } VarBindObject *VarBindQueue :: Delete () { VarBindObject *object = NULL ; if ( ! queue.IsEmpty () ) { object = queue.GetHead () ; queue.RemoveHead () ; } return object ; } VarBindObjectRequest :: VarBindObjectRequest ( const SnmpObjectIdentifierType &varBindArg ) : varBind ( varBindArg ) , requested ( varBindArg ) , repeatRequest ( TRUE ) { } VarBindObjectRequest :: VarBindObjectRequest ( const SnmpObjectIdentifierType &varBindArg , const SnmpObjectIdentifierType &requestedVarBindArg ) : varBind ( varBindArg ) , requested ( requestedVarBindArg ) , repeatRequest ( TRUE ) { } VarBindObjectRequest :: VarBindObjectRequest () : repeatRequest ( TRUE ) { } VarBindObjectRequest :: ~VarBindObjectRequest () { } const SnmpObjectIdentifierType &VarBindObjectRequest :: GetRequested () const { return requested ; } const SnmpObjectIdentifierType &VarBindObjectRequest :: GetVarBind () const { return varBind ; } void VarBindObjectRequest :: SetRequested ( const SnmpObjectIdentifierType &requestedArg ) { requested = requestedArg ; } void VarBindObjectRequest :: SetVarBind ( const SnmpObjectIdentifierType &varBindArg ) { varBind = varBindArg ; } void VarBindObjectRequest :: AddQueuedObject ( VarBindObject *object ) { varBindResponseQueue.Add ( object ) ; } VarBindObject *VarBindObjectRequest :: GetQueuedObject () { return varBindResponseQueue.Get () ; } VarBindObject *VarBindObjectRequest :: DeleteQueueudObject () { return varBindResponseQueue.Delete () ; } GetNextOperation :: GetNextOperation ( IN SnmpSession &session , SnmpAutoRetrieveOperation &autoRetrieveOperation ) : SnmpGetNextOperation ( session ) , operation ( NULL ) , minimumInstance ( NULL , 0 ) , cancelledRequest ( FALSE ) , m_RequestContainerLength ( 0 ) , m_RequestContainer ( NULL ) , m_RequestIndexContainer ( NULL ) { operation = &autoRetrieveOperation ; } GetNextOperation :: ~GetNextOperation () { Cleanup () ; delete [] m_RequestContainer ; delete [] m_RequestIndexContainer ; delete operation ; } void GetNextOperation :: Cleanup () { if ( m_RequestContainer ) { for ( ULONG t_Index = 0 ; t_Index < m_RequestContainerLength ; t_Index ++ ) { VarBindObjectRequest *varBindObjectRequest = m_RequestContainer [ t_Index ] ; m_RequestContainer [ t_Index ] = NULL ; delete varBindObjectRequest ; } } } void GetNextOperation :: SendRequest ( SnmpVarBindList &varBindList ) { cancelledRequest = FALSE ; ULONG t_Count = varBindList.GetLength () ; m_RequestContainerLength = t_Count ; m_RequestContainer = new VarBindObjectRequest * [ t_Count ] ; m_RequestIndexContainer = new ULONG [ t_Count ] ; ZeroMemory ( m_RequestContainer , sizeof ( VarBindObjectRequest * ) * t_Count ) ; ZeroMemory ( m_RequestIndexContainer , sizeof ( ULONG ) * t_Count ) ; ULONG t_Index = 0 ; varBindList.Reset () ; while ( varBindList.Next () ) { const SnmpVarBind *varBind = varBindList.Get () ; SnmpObjectIdentifierType requestObject ( varBind->GetInstance () ) ; VarBindObjectRequest *request = new VarBindObjectRequest ( requestObject ) ; m_RequestContainer [ t_Index ] = request ; t_Index ++ ; } Send () ; } void GetNextOperation :: SendRequest ( SnmpVarBindList &varBindList , SnmpVarBindList &startVarBindList ) { cancelledRequest = FALSE ; ULONG t_Count = varBindList.GetLength () ; m_RequestContainerLength = t_Count ; m_RequestContainer = new VarBindObjectRequest * [ t_Count ] ; m_RequestIndexContainer = new ULONG [ t_Count ] ; ULONG t_Index = 0 ; varBindList.Reset () ; startVarBindList.Reset () ; while ( startVarBindList.Next () && varBindList.Next () ) { const SnmpVarBind *varBind = varBindList.Get () ; const SnmpVarBind *startVarBind = startVarBindList.Get () ; SnmpObjectIdentifierType requestObject ( varBind->GetInstance () ) ; SnmpObjectIdentifierType startRequestObject ( startVarBind->GetInstance () ) ; VarBindObjectRequest *request = new VarBindObjectRequest ( requestObject , startRequestObject ) ; m_RequestContainer [ t_Index ] = request ; t_Index ++ ; } Send () ; } void GetNextOperation :: DestroyOperation () { SnmpGetNextOperation :: DestroyOperation () ; } void GetNextOperation :: CancelRequest () { cancelledRequest = TRUE ; SnmpGetNextOperation :: CancelRequest () ; } void GetNextOperation :: Send () { BOOL t_Count = 0 ; SnmpVarBindList sendVarBindList ; for ( ULONG t_Index = 0 ; t_Index < m_RequestContainerLength ; t_Index ++ ) { SnmpObjectIdentifierType objectIdentifierType ; VarBindObjectRequest *varBindObjectRequest = m_RequestContainer [ t_Index ] ; if ( varBindObjectRequest->GetRepeatRequest () ) { SnmpNull snmpNull ; SnmpVarBind varBind ( * ( SnmpObjectIdentifier * ) varBindObjectRequest->GetRequested ().GetValueEncoding () , snmpNull ) ; sendVarBindList.Add ( varBind ) ; m_RequestIndexContainer [ t_Count ] = t_Index ; t_Count ++ ; } } SnmpGetNextOperation :: SendRequest ( sendVarBindList ) ; } void GetNextOperation :: SentFrame ( IN const SessionFrameId session_frame_id , const SnmpErrorReport &errorReport ) { switch ( errorReport.GetError () ) { case Snmp_Success: { } break ; default: { } break ; } operation->SentFrame ( session_frame_id , errorReport ) ; SnmpGetNextOperation :: SentFrame ( session_frame_id , errorReport ) ; } void GetNextOperation :: ReceiveResponse () { BOOL receiveComplete = TRUE ; for ( ULONG t_Index = 0 ; t_Index < m_RequestContainerLength ; t_Index ++ ) { VarBindObjectRequest *varBindObjectRequest = m_RequestContainer [ t_Index ] ; if ( varBindObjectRequest->GetRepeatRequest () ) { receiveComplete = FALSE ; } } if ( ! cancelledRequest ) { // Check to see if we have finished if ( ! receiveComplete ) { // Request next response Send () ; } // Process received information while ( ProcessRow () ) ; } if ( receiveComplete ) { // We've finished operation->ReceiveResponse () ; // Clear all resources Cleanup () ; } } BOOL GetNextOperation :: ProcessRow () { // Process Row information BOOL initialised = FALSE ; BOOL objectHasNoValueAndIsRepeating = FALSE ; SnmpObjectIdentifier objectIdentifier ( NULL , 0 ) ; SnmpObjectIdentifier suffix ( NULL , 0 ) ; // Determine minimum instance for ( ULONG t_Index = 0 ; t_Index < m_RequestContainerLength ; t_Index ++ ) { VarBindObjectRequest *varBindObjectRequest = m_RequestContainer [ t_Index ] ; VarBindObject *queuedObject = varBindObjectRequest->GetQueuedObject () ; if ( queuedObject ) { // Get row information associated with table property, i.e. instance of initial varbind requested. SnmpObjectIdentifierType varBindType = varBindObjectRequest->GetVarBind () ; SnmpObjectIdentifier *varBind = ( SnmpObjectIdentifier * ) varBindType.GetValueEncoding () ; if(varBind) { BOOL t_Status = queuedObject->GetObjectIdentifier ().Suffix ( varBind->GetValueLength () , suffix ) ; if ( t_Status ) { if ( initialised ) { if ( suffix < objectIdentifier ) { // Least instance so far objectIdentifier = suffix ; } else { // Greater Than } } else { // objectIdentifier hasn't been set to a legal instance yet. objectIdentifier = suffix ; initialised = TRUE ; } } else { // No more rows as yet } } } else { if ( varBindObjectRequest->GetRepeatRequest () ) { objectHasNoValueAndIsRepeating = TRUE ; } } } if ( initialised && ( ! objectHasNoValueAndIsRepeating ) ) { minimumInstance = objectIdentifier ; // Process all columns which contain row of least minimum for ( ULONG t_Index = 0 ; t_Index < m_RequestContainerLength ; t_Index ++ ) { VarBindObjectRequest *varBindObjectRequest = m_RequestContainer [ t_Index ] ; VarBindObject *queuedObject = varBindObjectRequest->GetQueuedObject () ; if ( queuedObject ) { SnmpObjectIdentifierType varBindType = varBindObjectRequest->GetVarBind () ; SnmpObjectIdentifier *varBind = ( SnmpObjectIdentifier * ) varBindType.GetValueEncoding () ; if ( varBind && queuedObject->GetObjectIdentifier ().Suffix ( varBind->GetValueLength () , suffix ) ) { if ( suffix == minimumInstance ) { // Row to be processed SnmpNull snmpNull ; SnmpErrorReport errorReport ( Snmp_Success , Snmp_No_Error ) ; SnmpVarBind requestVarBind ( *varBind , snmpNull ) ; SnmpVarBind replyVarBind ( minimumInstance , queuedObject->GetValue () ) ; operation->ReceiveRowVarBindResponse ( t_Index + 1 , requestVarBind , replyVarBind , errorReport ) ; // Check CancelRequest hasn't been called in callback if ( cancelledRequest ) { return FALSE ; } // Remove row VarBindObject *queuedObject = varBindObjectRequest->DeleteQueueudObject () ; delete queuedObject ; } else { // Row is lexicographically greater than process row } } else { // Problem Here } } } // Forward call to AutoRetrieveOperation operation->ReceiveRowResponse () ; } else { // Zero rows to process } return initialised && ( ! objectHasNoValueAndIsRepeating ) ; } void GetNextOperation :: ReceiveVarBindResponse ( IN const ULONG &var_bind_index, IN const SnmpVarBind &requestVarBind , IN const SnmpVarBind &replyVarBind , IN const SnmpErrorReport &error ) { ULONG t_Index = m_RequestIndexContainer [ var_bind_index - 1 ] ; VarBindObjectRequest *varBindObjectRequest = m_RequestContainer [ t_Index ] ; /* * check for v2c errored responses */ if ( typeid ( replyVarBind.GetValue () ) == typeid ( SnmpEndOfMibView ) ) { // Stop further requests for this column varBindObjectRequest->SetRepeatRequest ( FALSE ) ; } else { // Locate request object // Check we haven't gone backwards lexicographically, which would result in an infinitely repeating request. if ( replyVarBind.GetInstance () > requestVarBind.GetInstance () ) { // Check we haven't reached end of table SnmpObjectIdentifier *objectIdentifier = ( SnmpObjectIdentifier *) varBindObjectRequest->GetVarBind ().GetValueEncoding () ; if ( objectIdentifier && replyVarBind.GetInstance().Equivalent ( *objectIdentifier , objectIdentifier->GetValueLength () ) ) { // Add row information to column of table SnmpObjectIdentifier snmpObjectIdentifier ( 0 , NULL ) ; SnmpObjectIdentifier suffix ( 0 , NULL ) ; SnmpNull snmpNull ; BOOL t_Status = replyVarBind.GetInstance().Suffix ( objectIdentifier->GetValueLength () , suffix ) ; if ( t_Status ) { SnmpVarBind sendVarBind ( snmpObjectIdentifier , snmpNull ) ; SnmpVarBind adjustedReplyVarBind ( suffix , replyVarBind.GetValue () ) ; LONG t_Option = operation->EvaluateNextRequest ( var_bind_index, requestVarBind , adjustedReplyVarBind , sendVarBind ) ; if ( t_Option == 0 ) { VarBindObject *varBindObject = new VarBindObject ( replyVarBind.GetInstance () , replyVarBind.GetValue () ) ; varBindObjectRequest->AddQueuedObject ( varBindObject ) ; // Update map to identify request next time around SnmpObjectIdentifierType replyObject ( replyVarBind.GetInstance () ) ; varBindObjectRequest->SetRequested ( replyObject ) ; } else if ( t_Option > 0 ) { VarBindObject *varBindObject = new VarBindObject ( replyVarBind.GetInstance () , replyVarBind.GetValue () ) ; varBindObjectRequest->AddQueuedObject ( varBindObject ) ; // Update map to identify request next time around SnmpObjectIdentifierType replyObject ( *objectIdentifier + sendVarBind.GetInstance () ) ; varBindObjectRequest->SetRequested ( replyObject ) ; } else { VarBindObject *varBindObject = new VarBindObject ( replyVarBind.GetInstance () , replyVarBind.GetValue () ) ; varBindObjectRequest->AddQueuedObject ( varBindObject ) ; varBindObjectRequest->SetRepeatRequest ( FALSE ) ; } } else { varBindObjectRequest->SetRepeatRequest ( FALSE ) ; } } else { // instance received is not row of column, i.e End Of Table varBindObjectRequest->SetRepeatRequest ( FALSE ) ; } } else { // instance requested is greater than instance replied varBindObjectRequest->SetRepeatRequest ( FALSE ) ; } } operation->ReceiveVarBindResponse ( var_bind_index,requestVarBind , replyVarBind , error ) ; } void GetNextOperation :: ReceiveErroredVarBindResponse( IN const ULONG &var_bind_index, IN const SnmpVarBind &requestVarBind , IN const SnmpErrorReport &error ) { ULONG t_Index = m_RequestIndexContainer [ var_bind_index - 1 ] ; VarBindObjectRequest *varBindObjectRequest = m_RequestContainer [ t_Index ] ; switch ( error.GetError () ) { case Snmp_Success: { /* * Can't happen */ } break ; default: { // Stop further requests for this column varBindObjectRequest->SetRepeatRequest ( FALSE ) ; } break ; } operation->ReceiveErroredVarBindResponse ( var_bind_index , requestVarBind , error ) ; } void GetNextOperation :: FrameTooBig () { operation->FrameTooBig () ; } void GetNextOperation :: FrameOverRun () { operation->FrameTooBig () ; } SnmpAutoRetrieveOperation :: SnmpAutoRetrieveOperation (IN SnmpSession &session) { operation = new GetNextOperation ( session , *this ) ; } SnmpAutoRetrieveOperation :: ~SnmpAutoRetrieveOperation () { } void SnmpAutoRetrieveOperation :: DestroyOperation () { operation->DestroyOperation () ; } void SnmpAutoRetrieveOperation :: CancelRequest () { operation->CancelRequest () ; } void SnmpAutoRetrieveOperation :: SendRequest ( SnmpVarBindList &varBindList ) { operation->SendRequest ( varBindList ) ; } void SnmpAutoRetrieveOperation :: SendRequest ( SnmpVarBindList &varBindList , SnmpVarBindList &startVarBindList ) { operation->SendRequest ( varBindList , startVarBindList ) ; }