Snmp Get
Posted: Wed Nov 02, 2005 4:34 pm
				
				Anybody has information how to implement this function in PureBasic ?
			Someone did some snmp code in the german forum, using an UDPnetwork lib (which I couldn't install, but this should be possible)...Droopy wrote:Anybody has information how to implement this function in PureBasic ?
Would be fine for me also - I used a very rude method: calling SNMPUtil.exe in a hidden window by different threads and capturing its output to memory...blueznl wrote:Looking for SNMP code examples... anyone that has a suggestion?
Code: Select all
Procedure.l Set_Integer      ( value.l )
  If value <= $7F
  
    *Integer = AllocateMemory ( 1 )
    PokeB ( *Integer, value )
    
  Else
  
    *Integer = AllocateMemory ( 2 )
    PokeB ( *Integer + 00, ( value & $FF00 ) >> 8 )
    PokeB ( *Integer + 01, value & $FF )
  
  EndIf
  
  ProcedureReturn *Integer
EndProcedure
Procedure.l Get_Integer      ( *Integer, free_memory.l )
  value = 0
  For position = 0 To MemorySize ( *Integer ) - 1
  
    value.l = ( x_value << 8 ) | PeekB ( *Integer + position )
    
  Next
  If free_memory = #True
    FreeMemory ( *Integer )
  EndIf
  ProcedureReturn value
EndProcedure
Procedure.l BER_Encode       ( value.q )
  *BER_Encode = #Null
  If value >= 0 And value < 128
    *BER_Encode = AllocateMemory ( 1 )
    PokeB ( *BER_Encode + 00, value )
    
  ElseIf value >= 128       And value < 16384
    *BER_Encode = AllocateMemory ( 2 )
    PokeB ( *BER_Encode + 00, $80 | ( value >> 7 ) )
    PokeB ( *BER_Encode + 01, value & $7f )
    
  ElseIf value >= 16384     And value < 2097152
    *BER_Encode = AllocateMemory ( 3 )
    PokeB ( *BER_Encode + 00, $80 | ( ( value >> 14 ) & $7f ) )
    PokeB ( *BER_Encode + 01, $80 | ( ( value >>  7 ) & $7f ) )
    PokeB ( *BER_Encode + 02, value & $7f )
    
  ElseIf value >= 2097152   And value < 268435456
    *BER_Encode = AllocateMemory ( 4 )
    PokeB ( *BER_Encode + 00, $80 | ( ( value >> 21 ) & $7f ) )
    PokeB ( *BER_Encode + 01, $80 | ( ( value >> 14 ) & $7f ) )
    PokeB ( *BER_Encode + 02, $80 | ( ( value >>  7 ) & $7f ) )
    PokeB ( *BER_Encode + 03, value & $7f )
    
  ElseIf value >= 268435456 And value < 4294967296
    *BER_Encode = AllocateMemory ( 5 )
    PokeB ( *BER_Encode + 00, $80 | ( ( value >> 28 ) & $0f ) )
    PokeB ( *BER_Encode + 01, $80 | ( ( value >> 21 ) & $7f ) )
    PokeB ( *BER_Encode + 02, $80 | ( ( value >> 14 ) & $7f ) )
    PokeB ( *BER_Encode + 03, $80 | ( ( value >>  7 ) & $7f ) )
    PokeB ( *BER_Encode + 04, value & $7f )
  EndIf
  ProcedureReturn *BER_Encode
EndProcedure
Procedure.l BER_Decode_2     ( *input_data, cut.l, free_memory.l )
  output_value.l = 0
  
  value_1.l = PeekB( *input_data + 00 ) & $FF
  value_2.l = PeekB( *input_data + 01 ) & $FF
  counter.l = 2
  
  If value_1 = $80
    output_value = $80
      
  ElseIf value_1 > $80 And value_2 > $80
    output_value = ( ( value_1 - $80 ) << 7 ) + ( value_2 - $80 )
    
  ElseIf value_1 > $80 And value_2 < $80
  
    output_value = ( ( value_1 - $80 ) << 7 ) + value_2
  
  ElseIf value_1 < $80
  
    output_value = value_1
    counter = 1
  
  EndIf
  If cut = #True
    CopyMemory ( *input_data + counter , *input_data, MemorySize ( *input_data ) - counter )
    ReAllocateMemory ( *input_data, MemorySize ( *input_data ) - counter )
  EndIf
  
  If free_memory = #True
    FreeMemory ( *input_data )
  EndIf
  
  ProcedureReturn output_value
EndProcedure
Procedure.l OID_Encode       ( oid_string.s )
  dot_numbers = CountString ( oid_string, "." )
  *OID_Encode       = AllocateMemory ( 1024 )
  OID_Encode_Length = 0
  
  If Left ( oid_string, 1 ) = "."
    oid_string = Mid ( oid_string, 2, Len ( oid_string ) - 1 )
  EndIf
  
  first  = Val ( StringField( oid_string, 1, "." ) )
  second = Val ( StringField( oid_string, 2, "." ) )
  
  first  = ( first * 40 ) + second
  
  *mem_value = BER_Encode ( first )
  
  CopyMemory ( *mem_value, *OID_Encode, MemorySize ( *mem_value ) )
  
  OID_Encode_Length + MemorySize ( *mem_value )
  
  FreeMemory ( *mem_value )
  
  If CountString ( oid_string, "." ) > 1
    For position.l = 3 To dot_numbers + 1
     
      *mem_value = BER_Encode ( Val ( StringField( oid_string, position, "." ) ) )
      CopyMemory ( *mem_value, *OID_Encode + OID_Encode_Length, MemorySize ( *mem_value ) )
      OID_Encode_Length + MemorySize ( *mem_value )
      FreeMemory ( *mem_value )
  
    Next
  EndIf
  
  ReAllocateMemory ( *OID_Encode, OID_Encode_Length )
  
  ProcedureReturn *OID_Encode
  
EndProcedure
Procedure.s OID_Decode       ( *OID_Decode )
  Dim OID.l ( 256 )
  
  OID_string.s  = ""
  OID_count     = 1
  subid         = 0
  For counter = 0 To MemorySize ( *OID_Decode ) - 1
    value = PeekB( *OID_Decode + counter ) & $FF
  
    If subid & $FE000000
      Debug "object too large"
    EndIf
    
    subid = ( subid << 7 ) | ( value & $7F )
    
    If Not( value & $80 )
      OID ( OID_count ) = subid
      OID_count + 1
      subid = 0
    
    EndIf
                    
  Next
  If OID ( 1 ) = 43
    OID ( 0 ) = 1
    OID ( 1 ) = 3
  ElseIf OID ( 1 ) < 64
    OID ( 0 ) = 0
  ElseIf OID ( 1 ) < 128
    OID ( 0 ) = 1
    OID ( 1 ) = 64
  Else
    OID ( 0 ) = 2
    OID ( 1 ) = 128
  EndIf
  For counter = 0 To OID_count - 1
    OID_string + "." + Str( OID ( counter ) )
  
  Next
  ProcedureReturn OID_string
EndProcedure
Procedure.l Make_TLV         ( type.b, *input_data, free_memory.l )
  Data_Length.l  = MemorySize   ( *input_data   )
  *Octet_Length  = Set_Integer  ( Data_Length   )
  Length.l       = MemorySize   ( *Octet_Length )
  *TLV = AllocateMemory ( 1 + Length + Data_Length )
  
  PokeB      ( *TLV, type )
  CopyMemory ( *Octet_Length, *TLV + 1         , Length)
  CopyMemory ( *input_data  , *TLV + 1 + Length, Data_Length )
  
  FreeMemory ( *Octet_Length )
  
  If free_memory = #True
    FreeMemory ( *input_data )
  EndIf
  
  ProcedureReturn *TLV
EndProcedure
Procedure.l Make_TLV_Null    ( type.b )
  *TLV = AllocateMemory ( 2 )
  
  PokeB ( *TLV + 00, type )
  PokeB ( *TLV + 01, 00   )
  
  ProcedureReturn *TLV
EndProcedure
Procedure.l Join_Data        ( *memory_1, *memory_2, free_memory.l )
  *Joined = AllocateMemory ( MemorySize ( *memory_1 ) + MemorySize ( *memory_2 ) )
  
  CopyMemory ( *memory_1, *Joined, MemorySize ( *memory_1 ) )
  CopyMemory ( *memory_2, *Joined + MemorySize ( *memory_1 ), MemorySize ( *memory_2 ) )
  
  If free_memory = #True
    FreeMemory ( *memory_1 )
    FreeMemory ( *memory_2 )
  EndIf
  
  ProcedureReturn *Joined
EndProcedure
Procedure.l Make_String      ( string.s )
  *String = AllocateMemory ( Len (string) )
  
  PokeS ( *String, string )
  
  ProcedureReturn *String
EndProcedure
Procedure.l Memory_Move_Left ( *memory, offset.l )
  If MemorySize ( *memory ) > offset
    CopyMemory ( *memory + offset, *memory, MemorySize ( *memory ) - offset )
    ReAllocateMemory ( *memory, MemorySize ( *memory ) - offset )
    ProcedureReturn #True
  EndIf
  
  ProcedureReturn #False
EndProcedure
Procedure.l Unpack_TLV       ( *input_data, cut_memory.l, free_memory.l )
  *TMP = AllocateMemory ( MemorySize ( *input_data ) - 1 )
  CopyMemory ( *input_data + 1, *TMP, MemorySize ( *TMP ) )
  
  type.l = PeekB ( *input_data ) & $FF
  
  return_value = #False
  cut_length = 0
  
  If type = $05
    cut_length = 2
  
  ElseIf type = $30 Or type > $9F
    ; SEQUENCE
    sequence_length = BER_Decode_2 ( *TMP, #True, #False )
    If sequence_length = MemorySize ( *TMP )
      return_value = *TMP
    EndIf
  Else
    ; Other
    Length = PeekB ( *TMP ) & $FF
    
    Memory_Move_Left ( *TMP, 1 )
    ReAllocateMemory ( *TMP, Length )
    
    return_value = *TMP
    cut_length = 2 + Length
    
  EndIf
  
  If cut_memory = #True
  
    Memory_Move_Left ( *input_data, cut_length )
  
  EndIf
  
  If free_memory = #True
    FreeMemory ( *input_data )
  
  EndIf
  ProcedureReturn return_value
EndProcedure
Procedure.l Make_SNMP_Packet  ( community_string.s, snmp_pdu.s, request_id.l, object_identifier.s )
  return_value = #False
  If UCase ( snmp_pdu ) = "GET_NEXT"
    SNMP_PDU_Type.l = $A1
    *Value = Make_TLV_Null ( $05 )
  
  Else ; GET
    SNMP_PDU_Type.l = $A0
    *Value = Make_TLV_Null ( $05 )
  
  EndIf
  ; [ SNMP_Message [ Version_Number ] [ Community_String ] [ SNMP_PDU [ Request_ID ] [ Error ] [ Error_Index ] [ Varbind_List [ Varbind [ Object_Identifier ] [ Value ] ] ] ] ]
  
  *OID = OID_Encode ( object_identifier )
  
  If *OID
    *Object_Identifier = Make_TLV ( $06, *OID, #True )
  EndIf
  
  If *Object_Identifier And *Value
    *Varbind_Data = Join_Data ( *Object_Identifier, *Value, #True )
  EndIf
  If *Varbind_Data
    *Varbind = Make_TLV ( $30, *Varbind_Data, #True )
  EndIf    
  If *Varbind
    *Varbind_List     = Make_TLV    ( $30, *Varbind, #True )
    *Request_ID_Value = Set_Integer ( request_id )
  EndIf
  If *Request_ID_Value And *Varbind_List
    *Request_ID  = Make_TLV ( $02, *Request_ID_Value, #True )
    *Error_Value = Set_Integer ( $00 )
  EndIf
              
  If *Request_ID And *Error_Value
    *Error             = Make_TLV ( $02, *Error_Value, #True )
    *Error_Index_Value = Set_Integer ( $00 )
  EndIf          
  If *Error And *Error_Index_Value
    *Error_Index = Make_TLV ( $02, *Error_Index_Value, #True )
    *Temp_1      = Join_Data ( *Request_ID, *Error, #True )
  EndIf
                    
  If *Error_Index And *Temp_1
    *Temp_2 = Join_Data ( *Temp_1, *Error_Index, #True )
  EndIf                  
  If *Temp_2
    *SNMP_PDU_Data = Join_Data ( *Temp_2, *Varbind_List, #True )
  EndIf
                    
  If *SNMP_PDU_Data
    *SNMP_PDU                    = Make_TLV    ( SNMP_PDU_Type, *SNMP_PDU_Data, #True )
    *SNMP_Community_String_Value = Make_String ( community_string )
  EndIf
                    
  If *SNMP_PDU And *SNMP_Community_String_Value
    *SNMP_Community_String = Make_TLV ( $04, *SNMP_Community_String_Value, #True )
    *SNMP_Version_Value    = Set_Integer   ( $00 )
  EndIf
                          
  If *SNMP_Community_String And *SNMP_Version_Value
    *SNMP_Version = Make_TLV ( $02, *SNMP_Version_Value, #True )
  EndIf
                            
  If *SNMP_Version
    *Temp_3 = Join_Data ( *SNMP_Version, *SNMP_Community_String, #True )
  EndIf
                              
  If *Temp_3
    *SNMP_Message_Data = Join_Data ( *Temp_3, *SNMP_PDU, #True )
  EndIf                          
  If *SNMP_Message_Data
    *SNMP_Message = Make_TLV ( $30, *SNMP_Message_Data, #True )
    return_value  = *SNMP_Message
  EndIf                            
  ProcedureReturn return_value
  
EndProcedure
Procedure.l Unpack_SNMP_Response ( *SNMP_Packet, request_id.l )
  return_value = #False
  
  *SNMP_Message = Unpack_TLV ( *SNMP_Packet, #True, #False )
  
  If *SNMP_Message
  
    *SNMP_Version = Unpack_TLV ( *SNMP_Message, #True, #False )
    
    If *SNMP_Version
    
      *SNMP_Community = Unpack_TLV ( *SNMP_Message, #True, #False )
      
      If *SNMP_Community
      
        SNMP_Version_Value.l   = Get_Integer ( *SNMP_Version, #True )
        SNMP_Community_Value.s = PeekS       ( *SNMP_Community, MemorySize ( *SNMP_Community ) )
        FreeMemory ( *SNMP_Community )
        
        *SNMP_PDU = Unpack_TLV ( *SNMP_Message, #True, #True )
        
        If *SNMP_PDU
        
          *Request_ID  = Unpack_TLV ( *SNMP_PDU, #True, #False )
          *Error       = Unpack_TLV ( *SNMP_PDU, #True, #False )
          *Error_Index = Unpack_TLV ( *SNMP_PDU, #True, #False )
          
          *Varbind_List = Unpack_TLV ( *SNMP_PDU, #True, #True )
          
          Request_ID = Get_Integer ( *Request_ID, #True )
;           Debug Request_ID
          
          If *Varbind_List
            *Varbind = Unpack_TLV ( *Varbind_List, #True, #True )
            return_value = *Varbind
          
          EndIf
        EndIf
      EndIf
    EndIf
  EndIf
  ProcedureReturn return_value
EndProcedure
Procedure.l SNMP_Send_And_Receieve ( ip_address.s, community.s, oid.s, type.s)
  return_value.l = #False
  
  If ip_address <> ""
    *ptr                = sockinfo.sockaddr_in
    sockinfo\sin_family = #AF_INET
    sockinfo\sin_port   = htons_(161)
    sockinfo\sin_addr   = inet_addr_(ip_address)
    SockIdent           = SOCKET_(#AF_INET, 2, 0)  ;create socket (#SOCK_DGRAM for UDP)	
    If SockIdent = #INVALID_SOCKET		
;       Debug "Socket cant be created!"	
    Else 		
;       Debug "UDP socket created!"
      RandomSeed ( Random ( 99999 ) )
      Request_ID = Random ( 99999 )
      *packet  = Make_SNMP_Packet ( community, type, Request_ID, oid )
      
      If *packet
      
        packet_length = MemorySize ( *packet )
        send = sendto_(SockIdent, *packet, packet_length, 0, *ptr, SizeOf(sockaddr_in))
        
        If send <> #SOCKET_ERROR 
        
          *recv_buffer     = AllocateMemory ( 512 )
          
          If *recv_buffer
            recv_buffer_size = MemorySize ( *recv_buffer )
          
            start = Date ()
            Repeat 
  
              Delay(1) 
              bytesRecv = recv_(SockIdent, *recv_buffer, recv_buffer_size, 2) 
              
              If Date () - start > 5
                bytesRecv = #SOCKET_ERROR
                Break
              
              EndIf
  
            Until bytesRecv <> -1 
  
            If bytesRecv <> #SOCKET_ERROR
            
              ReAllocateMemory(*recv_buffer, bytesRecv)
              
              *value = Unpack_SNMP_Response ( *recv_buffer, Request_ID )
              If *value
              
                 return_value = *value
                    
              EndIf
              
            EndIf
            
            FreeMemory ( *recv_buffer )
            
          EndIf
        EndIf
        FreeMemory (*packet)
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn return_value
EndProcedure
Procedure.l Decode_Result ( *result )
  type    = PeekB ( *result + 00 ) & $FF
  length  = PeekB ( *result + 01 ) & $FF
  
  If type = $06
  
    *oid    = AllocateMemory (length)
    CopyMemory (*result + 2, *oid, length)
    oid_s.s = OID_Decode ( *oid )
    FreeMemory ( *oid )
    
    Debug oid_s
    
    Memory_Move_Left ( *result, length + 2 )
  
  EndIf
  
  type    = PeekB ( *result + 00 ) & $FF
  length  = PeekB ( *result + 01 ) & $FF
  
  If type = $04 And length > 0
    
    *tmp = AllocateMemory ( length )
    
    CopyMemory ( *result + 2, *tmp, length)
    
    Debug PeekS ( *tmp, length )
  
  EndIf
  
  FreeMemory ( *result )
EndProcedure
Procedure ping (sIPAddress.s)
  EchoMessage.s = "Echo" 
  ResultSize.l = SizeOf(ICMP_ECHO_REPLY) + Len(EchoMessage) 
  *Result = AllocateMemory(ResultSize) 
  *Echo.ICMP_ECHO_REPLY = *Result 
  result = #False
   
  If Len(sIPAddress ) > 0 
    hFile.l = IcmpCreateFile_() 
    IPAddress.l = MakeIPAddress(Val(StringField(sIPAddress,1,".")),Val(StringField(sIPAddress,2,".")),Val(StringField(sIPAddress,3,".")),Val(StringField(sIPAddress+".",4,".")))  
    lngResult.l = IcmpSendEcho_(hFile, IPAddress, EchoMessage, Len(EchoMessage), 0, *Result, ResultSize, 500) 
        If lngResult
          result = #True
;           Debug ("Ping " + sIPAddress + " Octets: " + Str(*Echo\DataSize) + " Temps: " + Str(*Echo\RoundTripTime) + " ms TTL:" + StrU(*Echo\Options\Ttl,#Byte)) 
        EndIf
      IcmpCloseHandle_(hFile) 
    EndIf 
  
  FreeMemory(*Result) 
  ProcedureReturn result
EndProcedure
If InitNetwork()
    
  IPAddress.s = "192.168.1.25"
    
  Debug IPAddress
        
  If ping (IPAddress)
    *rec = SNMP_Send_And_Receieve ( IPAddress, "public", "1.3.6.1.2.1.1.1.0", "GET") ; or GET_NEXT
    If *rec
      Decode_Result ( *rec )
    EndIf
      
  EndIf
  Debug "------------------"
EndIf
Code: Select all
00 02 3F B1 4E AF 00 0E 6A CC 32 28 08 00 45 00   ..?±N¯..jÌ2(..E.
00 6A 01 A2 00 00 40 11 63 E0 AC 10 DE DE AC 10   .j.¢..@.cà¬.ÞÞ¬.
DE 01 00 A1 0C 23 00 56 32 96 30 82 00 4A 02 01   Þ..¡.#.V2?0?.J..
00 04 06 70 75 62 6C 69 63 A2 82 00 3B 02 02 A1   ...public¢?.;..¡
C9 02 01 00 02 01 00 30 82 00 2D 30 82 00 29 06   É......0?.-0?.).
08 2B 06 01 02 01 01 01 00 04 1D 42 72 6F 61 64   .+.........Broad
62 61 6E 64 20 52 65 73 69 64 65 6E 74 69 61 6C   band Residential 
20 47 61 74 65 77 61 79                           Gateway 
Code: Select all
172.16.222.222                                                                                                                                                                                       
PING OK                                                                                                                                                                                              
S&R I: 0'30' ‚'82' J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B'     
Unpack I: 0'30' ‚'82' J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B'  
TLV I: ‚'82' J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B' '6'      
TLV II: J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B' '6' '1' '2' 
ÖHA?256 / 75                                                                                                                                                                                         
Cut: 0'30' ‚'82' J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B'       
Return:  - <<EMPTY>>                                                                                                                                                                                 
Unpack II:  - <<EMPTY>>                                                                                                                                                                              
S&R II:  - <<EMPTY>>                                                                                                                                                                             
Main:  - <<EMPTY>>Code: Select all
Procedure DebugString(s.s,*mem)
Protected i,b
If *mem
For i=0 To 39
	b=PeekB(*mem+i)
	s=s+Chr(b)+"'"+Hex(b&$FF)+"' "	
Next i
Else
s+ " - <<EMPTY>>"
EndIf
Debug s
EndProcedure
Procedure.l Set_Integer(value.l)
	If value <= $7F
		*Integer=AllocateMemory(1)
		PokeB(*Integer,value)
	Else
		*Integer=AllocateMemory(2)
		PokeB(*Integer + 00,(value & $FF00) >> 8)
		PokeB(*Integer + 01,value & $FF)
	EndIf
	ProcedureReturn *Integer
EndProcedure
Procedure.l Get_Integer(*Integer,free_memory.l)
	value=0
	For position=0 To MemorySize(*Integer) - 1
		value.l=(x_value << 8) | PeekB(*Integer + position)
	Next
	If free_memory=#True
		FreeMemory(*Integer)
	EndIf
	ProcedureReturn value
EndProcedure
Procedure.l BER_Encode(value.q)
	*BER_Encode=#Null
;Debug -value
	If value >= 0 And value < 128
		*BER_Encode=AllocateMemory(1)
		PokeB(*BER_Encode + 00,value)
	ElseIf value >= 128       And value < 16384
		*BER_Encode=AllocateMemory(2)
		PokeB(*BER_Encode + 00,$80 |(value >> 7))
		PokeB(*BER_Encode + 01,value & $7f)
	ElseIf value >= 16384     And value < 2097152
		*BER_Encode=AllocateMemory(3)
		PokeB(*BER_Encode + 00,$80 |((value >> 14) & $7f))
		PokeB(*BER_Encode + 01,$80 |((value >>  7) & $7f))
		PokeB(*BER_Encode + 02,value & $7f)
	ElseIf value >= 2097152   And value < 268435456
		*BER_Encode=AllocateMemory(4)
		PokeB(*BER_Encode + 00,$80 |((value >> 21) & $7f))
		PokeB(*BER_Encode + 01,$80 |((value >> 14) & $7f))
		PokeB(*BER_Encode + 02,$80 |((value >>  7) & $7f))
		PokeB(*BER_Encode + 03,value & $7f)
	ElseIf value >= 268435456 And value < 4294967296
		*BER_Encode=AllocateMemory(5)
		PokeB(*BER_Encode + 00,$80 |((value >> 28) & $0f))
		PokeB(*BER_Encode + 01,$80 |((value >> 21) & $7f))
		PokeB(*BER_Encode + 02,$80 |((value >> 14) & $7f))
		PokeB(*BER_Encode + 03,$80 |((value >>  7) & $7f))
		PokeB(*BER_Encode + 04,value & $7f)
	EndIf
	ProcedureReturn *BER_Encode
EndProcedure
Procedure.l BER_Decode_2(*input_data,cut.l,free_memory.l)
	output_value.l=0
	value_1.l=PeekB(*input_data+00)&$FF
	value_2.l=PeekB(*input_data+01)&$FF
	counter.l=2
	If value_1=$80
		output_value=$80
	ElseIf value_1 > $80 And value_2 > $80
		output_value=((value_1 - $80) << 7) +(value_2 - $80)
	ElseIf value_1 > $80 And value_2 < $80
		output_value=((value_1 - $80) << 7) + value_2
	ElseIf value_1 < $80
		output_value=value_1
		counter=1
	EndIf
	If cut=#True
		CopyMemory(*input_data + counter,*input_data,MemorySize(*input_data) - counter)
		ReAllocateMemory(*input_data,MemorySize(*input_data) - counter)
	EndIf
	If free_memory=#True
		FreeMemory(*input_data)
	EndIf
	ProcedureReturn output_value
EndProcedure
Procedure.l OID_Encode(oid_string.s)
	dot_numbers=CountString(oid_string,".")
	*OID_Encode=AllocateMemory(1024)
	OID_Encode_Length=0
	If Left(oid_string,1)="."
		oid_string=Mid(oid_string,2,Len(oid_string) - 1)
	EndIf
	first=Val(StringField(oid_string,1,"."))
	second=Val(StringField(oid_string,2,"."))
	first=(first * 40) + second
	*mem_value=BER_Encode(first)
	CopyMemory(*mem_value,*OID_Encode,MemorySize(*mem_value))
	OID_Encode_Length + MemorySize(*mem_value)
	FreeMemory(*mem_value)
	If CountString(oid_string,".") > 1
		For position.l=3 To dot_numbers + 1
			*mem_value=BER_Encode(Val(StringField(oid_string,position,".")))
			CopyMemory(*mem_value,*OID_Encode + OID_Encode_Length,MemorySize(*mem_value))
			OID_Encode_Length + MemorySize(*mem_value)
			FreeMemory(*mem_value)
		Next
	EndIf
	ReAllocateMemory(*OID_Encode,OID_Encode_Length)
	ProcedureReturn *OID_Encode
EndProcedure
Procedure.s OID_Decode(*OID_Decode)
	Dim OID.l(256)
	OID_string.s=""
	OID_count=1
	subid=0
	For counter=0 To MemorySize(*OID_Decode) - 1
		value=PeekB(*OID_Decode + counter) & $FF
		If subid & $FE000000
			Debug "object too large"
		EndIf
		subid=(subid << 7) |(value & $7F)
		If Not(value & $80)
			OID(OID_count)=subid
			OID_count + 1
			subid=0
		EndIf
	Next
	If OID(1)=43
		OID(0)=1
		OID(1)=3
	ElseIf OID(1) < 64
		OID(0)=0
	ElseIf OID(1) < 128
		OID(0)=1
		OID(1)=64
	Else
		OID(0)=2
		OID(1)=128
	EndIf
	For counter=0 To OID_count - 1
		OID_string + "." + Str(OID(counter))
	Next
	ProcedureReturn OID_string
EndProcedure
Procedure.l Make_TLV(type.b,*input_data,free_memory.l)
	Data_Length.l=MemorySize(*input_data  )
	*Octet_Length=Set_Integer(Data_Length  )
	Length.l=MemorySize(*Octet_Length)
	*TLV=AllocateMemory(1 + Length + Data_Length)
	PokeB(*TLV,type)
	CopyMemory(*Octet_Length,*TLV + 1        ,Length)
	CopyMemory(*input_data ,*TLV + 1 + Length,Data_Length)
	FreeMemory(*Octet_Length)
	If free_memory=#True
		FreeMemory(*input_data)
	EndIf
	ProcedureReturn *TLV
EndProcedure
Procedure.l Make_TLV_Null(type.b)
	*TLV=AllocateMemory(2)
	PokeB(*TLV + 00,type)
	PokeB(*TLV + 01,00  )
	ProcedureReturn *TLV
EndProcedure
Procedure.l Join_Data(*memory_1,*memory_2,free_memory.l)
	*Joined=AllocateMemory(MemorySize(*memory_1) + MemorySize(*memory_2))
	CopyMemory(*memory_1,*Joined,MemorySize(*memory_1))
	CopyMemory(*memory_2,*Joined + MemorySize(*memory_1),MemorySize(*memory_2))
	If free_memory=#True
		FreeMemory(*memory_1)
		FreeMemory(*memory_2)
	EndIf
	ProcedureReturn *Joined
EndProcedure
Procedure.l Make_String(string.s)
	*String=AllocateMemory(Len(string))
	PokeS(*String,string)
	ProcedureReturn *String
EndProcedure
Procedure.l Memory_Move_Left(*memory,offset.l)
	If MemorySize(*memory) > offset
		CopyMemory(*memory + offset,*memory,MemorySize(*memory) - offset)
		ReAllocateMemory(*memory,MemorySize(*memory) - offset)
		ProcedureReturn #True
	EndIf
	ProcedureReturn #False
EndProcedure
Procedure.l Unpack_TLV(*input_data,cut_memory.l,free_memory.l)
	*TMP=AllocateMemory(MemorySize(*input_data) - 1)
	CopyMemory(*input_data + 1,*TMP,MemorySize(*TMP))
	type.l=PeekB(*input_data) & $FF
	return_value=#False
	cut_length=0
	If type=$05
		cut_length=2
	ElseIf type=$30 Or type > $9F
DebugString("TLV I: ",*TMP)
		; SEQUENCE
		sequence_length=BER_Decode_2(*TMP,#True,#False)
DebugString("TLV II: ",*TMP)
		If sequence_length=MemorySize(*TMP)
			return_value=*TMP
		Else
		Debug "ÖHA?"+Str(sequence_length)+" / "+Str(MemorySize(*tmp))
		EndIf
	Else
		; Other
		Length=PeekB(*TMP) & $FF
		Memory_Move_Left(*TMP,1)
		ReAllocateMemory(*TMP,Length)
		return_value=*TMP
		cut_length=2 + Length
	EndIf
	If cut_memory=#True
		Memory_Move_Left(*input_data,cut_length)
DebugString("Cut: ",*input_data)
	EndIf
	If free_memory=#True
	FreeMemory(*input_data)
	EndIf
DebugString("Return: ",return_value)
	ProcedureReturn return_value
EndProcedure
Procedure.l Make_SNMP_Packet(community_string.s,snmp_pdu.s,request_id.l,object_identifier.s)
	return_value=#False
	If UCase(snmp_pdu)="GET_NEXT"
		SNMP_PDU_Type.l=$A1
		*Value=Make_TLV_Null($05)
	Else ; GET
		SNMP_PDU_Type.l=$A0
		*Value=Make_TLV_Null($05)
	EndIf
	; [ SNMP_Message [ Version_Number ] [ Community_String ] [ SNMP_PDU [ Request_ID ] [ Error ] [ Error_Index ] [ Varbind_List [ Varbind [ Object_Identifier ] [ Value ] ] ] ] ]
	*OID=OID_Encode(object_identifier)
	If *OID
		*Object_Identifier=Make_TLV($06,*OID,#True)
	EndIf
	If *Object_Identifier And *Value
		*Varbind_Data=Join_Data(*Object_Identifier,*Value,#True)
	EndIf
	If *Varbind_Data
		*Varbind=Make_TLV($30,*Varbind_Data,#True)
	EndIf
	If *Varbind
		*Varbind_List=Make_TLV($30,*Varbind,#True)
		*Request_ID_Value=Set_Integer(request_id)
	EndIf
	If *Request_ID_Value And *Varbind_List
		*Request_ID=Make_TLV($02,*Request_ID_Value,#True)
		*Error_Value=Set_Integer($00)
	EndIf
	If *Request_ID And *Error_Value
		*Error=Make_TLV($02,*Error_Value,#True)
		*Error_Index_Value=Set_Integer($00)
	EndIf
	If *Error And *Error_Index_Value
		*Error_Index=Make_TLV($02,*Error_Index_Value,#True)
		*Temp_1=Join_Data(*Request_ID,*Error,#True)
	EndIf
	If *Error_Index And *Temp_1
		*Temp_2=Join_Data(*Temp_1,*Error_Index,#True)
	EndIf
	If *Temp_2
		*SNMP_PDU_Data=Join_Data(*Temp_2,*Varbind_List,#True)
	EndIf
	If *SNMP_PDU_Data
		*SNMP_PDU=Make_TLV(SNMP_PDU_Type,*SNMP_PDU_Data,#True)
		*SNMP_Community_String_Value=Make_String(community_string)
	EndIf
	If *SNMP_PDU And *SNMP_Community_String_Value
		*SNMP_Community_String=Make_TLV($04,*SNMP_Community_String_Value,#True)
		*SNMP_Version_Value=Set_Integer($00)
	EndIf
	If *SNMP_Community_String And *SNMP_Version_Value
		*SNMP_Version=Make_TLV($02,*SNMP_Version_Value,#True)
	EndIf
	If *SNMP_Version
		*Temp_3=Join_Data(*SNMP_Version,*SNMP_Community_String,#True)
	EndIf
	If *Temp_3
		*SNMP_Message_Data=Join_Data(*Temp_3,*SNMP_PDU,#True)
	EndIf
	If *SNMP_Message_Data
		*SNMP_Message=Make_TLV($30,*SNMP_Message_Data,#True)
		return_value=*SNMP_Message
	EndIf
	ProcedureReturn return_value
EndProcedure
Procedure.l Unpack_SNMP_Response(*SNMP_Packet,request_id.l)
	return_value=#False
DebugString("Unpack I: ",*snmp_packet)
	*SNMP_Message=Unpack_TLV(*SNMP_Packet,#True,#False)
DebugString("Unpack II: ",*snmp_message)
	If *SNMP_Message
		*SNMP_Version=Unpack_TLV(*SNMP_Message,#True,#False)
		If *SNMP_Version
			*SNMP_Community=Unpack_TLV(*SNMP_Message,#True,#False)
			If *SNMP_Community
				SNMP_Version_Value.l=Get_Integer(*SNMP_Version,#True)
				SNMP_Community_Value.s=PeekS(*SNMP_Community,MemorySize(*SNMP_Community))
				FreeMemory(*SNMP_Community)
				*SNMP_PDU=Unpack_TLV(*SNMP_Message,#True,#True)
				If *SNMP_PDU
					*Request_ID=Unpack_TLV(*SNMP_PDU,#True,#False)
					*Error=Unpack_TLV(*SNMP_PDU,#True,#False)
					*Error_Index=Unpack_TLV(*SNMP_PDU,#True,#False)
					*Varbind_List=Unpack_TLV(*SNMP_PDU,#True,#True)
					Request_ID=Get_Integer(*Request_ID,#True)
					;           Debug Request_ID
					If *Varbind_List
						*Varbind=Unpack_TLV(*Varbind_List,#True,#True)
						return_value=*Varbind
					EndIf
				EndIf
			EndIf
		EndIf
	EndIf
	ProcedureReturn return_value
EndProcedure
Procedure.l SNMP_Send_And_Receive(ip_address.s,community.s,oid.s,type.s)
	return_value.l=#False
	If ip_address<>""
		*ptr=sockinfo.sockaddr_in
		sockinfo\sin_family=#AF_INET
		sockinfo\sin_port=htons_(161)
		sockinfo\sin_addr=inet_addr_(ip_address)
		SockIdent=SOCKET_(#AF_INET,2,0)  ;create socket (#SOCK_DGRAM for UDP)
		If SockIdent=#INVALID_SOCKET
			       Debug "Socket cant be created!"
		Else
		;	       Debug "UDP socket created!"
			RandomSeed(Random(99999))
			Request_ID=Random(99999)
			*packet=Make_SNMP_Packet(community,type,Request_ID,oid)
			If *packet
				packet_length=MemorySize(*packet)
				send=sendto_(SockIdent,*packet,packet_length,0,*ptr,SizeOf(sockaddr_in))
				If send<>#SOCKET_ERROR
					*recv_buffer=AllocateMemory(512)
					If *recv_buffer
						recv_buffer_size=MemorySize(*recv_buffer)
						
			;			Debug recv_buffer_size
						start=Date()
						Repeat
							Delay(1)
							bytesRecv=recv_(SockIdent,*recv_buffer,recv_buffer_size,2)
							If Date()-start>5
								bytesRecv=#SOCKET_ERROR
								Break
							EndIf
						Until bytesRecv<>-1
				;		Debug bytesRecv
						DebugString("S&R I: ",*recv_buffer)
						If bytesRecv<>#SOCKET_ERROR
							ReAllocateMemory(*recv_buffer,bytesRecv)
							*value=Unpack_SNMP_Response(*recv_buffer,Request_ID)
							If *value
								return_value=*value
							EndIf
						EndIf
						DebugString("S&R II: ",*value)
						
						FreeMemory(*recv_buffer)
					EndIf
				EndIf
				FreeMemory(*packet)
			EndIf
		EndIf
	EndIf
	ProcedureReturn return_value
EndProcedure
Procedure.l Decode_Result(*result)
	type=PeekB(*result + 00) & $FF
	length=PeekB(*result + 01) & $FF
	If type=$06
		*oid=AllocateMemory(length)
		CopyMemory(*result + 2,*oid,length)
		oid_s.s=OID_Decode(*oid)
		FreeMemory(*oid)
		Debug oid_s
		MessageRequester("OID S",oid_s)
		Memory_Move_Left(*result,length + 2)
	EndIf
	type=PeekB(*result + 00) & $FF
	length=PeekB(*result + 01) & $FF
	If type=$04 And length > 0
		*tmp=AllocateMemory(length)
		CopyMemory(*result + 2,*tmp,length)
		Debug PeekS(*tmp,length)
		MessageRequester("Tpe 4",PeekS(*tmp,length))
	EndIf
	debugstring("Decode: ",*result)
	FreeMemory(*result)
EndProcedure
Procedure ping(sIPAddress.s)
	EchoMessage.s="Echo"
	ResultSize.l=SizeOf(ICMP_ECHO_REPLY) + Len(EchoMessage)
	*Result=AllocateMemory(ResultSize)
	*Echo.ICMP_ECHO_REPLY=*Result
	result=#False
	If Len(sIPAddress) > 0
		hFile.l=IcmpCreateFile_()
		IPAddress.l=MakeIPAddress(Val(StringField(sIPAddress,1,".")),Val(StringField(sIPAddress,2,".")),Val(StringField(sIPAddress,3,".")),Val(StringField(sIPAddress+".",4,".")))
		lngResult.l=IcmpSendEcho_(hFile,IPAddress,EchoMessage,Len(EchoMessage),0,*Result,ResultSize,500)
		If lngResult
			result=#True
			;           Debug ("Ping " + sIPAddress + " Octets: " + Str(*Echo\DataSize) + " Temps: " + Str(*Echo\RoundTripTime) + " ms TTL:" + StrU(*Echo\Options\Ttl,#Byte))
		EndIf
		IcmpCloseHandle_(hFile)
	EndIf
	FreeMemory(*Result)
	ProcedureReturn result
EndProcedure
If InitNetwork()
	IPAddress.s="172.16.222.222"
	Debug IPAddress
	If ping(IPAddress)
		;MessageRequester("Ping",ipaddress+" successfull.")
Debug "PING OK"
		*rec=SNMP_Send_And_Receive(IPAddress,"public","1.3.6.1.2.1.1.1.0","GET") ; or GET_NEXT
		debugstring("Main: ",*rec)
		If *rec
		Debug "REC"
			;MessageRequester("GET",PeekS(*rec))
			Decode_Result(*rec)
		
		EndIf
		
	EndIf
	Debug "------------------"
EndIfCode: Select all
Packet.s="30 82 00 4A 02 01 00 04 06 70 75 62 6C 69 63 A2 82 00 3B 02 02 C7 2B 02 01 00 02 01 00 30 82 00 2D 30 82 00 29 06 08 2B 06 01 02 01 01 01 00 04 1D 42 72 6F 61 64 62 61 6E 64 20 52 65 73 69 64 65 6E 74 69 61 6C 20 47 61 74 65 77 61 79 "
Global FrameLength=Len(Packet.s)/3
Global FrameData.s=Space(FrameLength)
For i=0 To FrameLength-1
PokeB(@FrameData+i,Val("$"+Mid(Packet,i*3+1,2)))
Next i
Procedure DebugString(s.s,*mem)
Protected i,b
If *mem
For i=0 To 39
	b=PeekB(*mem+i)&$ff
	If b>31
		s=s+Hex(b&$FF)+"|"+Chr(b)+" "	
	Else
		s=s+RSet(Hex(b),2,"0")+"|. "	
	EndIf
Next i
Else
s+ " - <<EMPTY>>"
EndIf
Debug s
EndProcedure
Structure Reference
	value.l
EndStructure
Procedure.l BER_Length(*memory,*pos.Reference)
	
	Protected byte
	Protected length
	Protected n
		
	byte=PeekB(*memory+*pos\Value)
	*pos\Value+1
				
	If byte&$80;				multi-byte length
		byte&$3;					number of bytes For length information
			
		While byte
			length<<8
			length+(PeekB(*memory+*pos\Value)&$ff)
			byte-1
			*pos\Value+1
		Wend
	Else
		length=byte&$7f
	EndIf	
;Debug "Len: "+Str(length)
	ProcedureReturn length
EndProcedure
Procedure.l BER_Integer(*memory,length)
Protected n
While length
			n<<8
			n+(PeekB(*memory)&$ff)
			length-1
			*memory+1
		Wend
		ProcedureReturn n
EndProcedure
Procedure.s BER_Object(*memory,length)
Protected byte
Protected OID.s
While length
byte=PeekB(*memory)&$ff
If byte='+'
	OID="1.3"
Else
OID+"."+Chr('0'+PeekB(*memory))
EndIf
*memory+1
length-1
Wend
ProcedureReturn OID
EndProcedure
Procedure.l BER_Class(*memory)
	Protected byte
	Protected length
	Protected pos
	; Class (Bits 7/8)
	; 0 - Universal (integer, string etc.)
	; 1 - Application (IP address)
	; 2 - Context (complex data)
	; 3 - Private (non standard data)
	
	; Data Type (Bit 6)
	; 0 - primitive data-type
	; 1 - constucted data-type
	; ASN.1 Type (Bit 5)
	; 0 - no
	; 1 - yes
pos=0
For i=1 To 12
	
	byte=PeekB(*memory+pos)&$ff
	Debug "----------"
	Debug "Pos: "+Str(pos)+" (=$"+Hex(byte&$ff)+")"
	pos+1
	
	Select byte>>6;					class...
	
	Case 0;										universal class
		If byte&$20;						constructed data type
			If byte&$10;					ASN.1
				length=BER_Length(*memory,@pos);
			EndIf
						
		Else;										primitive data type
			
			length=BER_Length(*memory,@pos);
			
			Select byte&$f
			Case 2
				Debug "integer: "+Str(BER_Integer(*memory+pos,length))
			Case 3
				Debug "bit string"
			Case 4
				Debug "octet string: "+PeekS(*memory+pos,length)
			Case 5
				Debug "null"
			Case 6
				Debug "object: "+BER_Object(*memory+pos,length)
			EndSelect
			
		pos+length
		EndIf
	
	Case 2;											context specific
	
		Debug "SNMP"
		If byte&$20;						constructed data type
			length=BER_Length(*memory,@pos);
				Debug "S:"+Str(length)
		Else;										primitive data type
			Debug "?"
		EndIf
		
	EndSelect
Next i
	
EndProcedure
DebugString("Init:",@FrameData)
BER_Class(@FrameData)
Code: Select all
; Define
	EnableExplicit
	; Alive state
	Enumeration
		#Station_Unknown
		#Station_Down
		#Station_Up
	EndEnumeration
	; GetType
	Enumeration $A0
		#GET
		#GET_NEXT
	EndEnumeration
	; Status
	Enumeration
		#SNMP_Unknown
		#SNMP_Ok
		#SNMP_Sent
		#SNMP_Received
		#SNMP_Error
		#SNMP_Error_OID
		#SNMP_Error_RID
		#SNMP_Error_Name
	EndEnumeration
	
	;ValueType
	Enumeration
		#TypeUnknown
		#TypeInteger
		#TypeString
		#TypeIP
		#TypeTicks
		#TypeObject
	EndEnumeration
	; internally used
	Enumeration
		#Field_Header
		#Field_Version
		#Field_Community
		#Field_PDU
		#Field_RequestID
		#Field_ErrorState
		#Field_ErrorIndex
		#Field_VariableLengthWithHeader
		#Field_VariableLengthWithoutHeader
		#Field_OID
		#Field_Variable
		#Field_Nil
	EndEnumeration
	#SNMP_MaxPacketSize=548
	Structure Reference
		value.l
	EndStructure
	Structure StationType
		IP.l
		Community.s
		Alive.w
	EndStructure
	Structure SNMPType
		StationNumber.w
		GetType.w
		RequestID.w
		OID.s
		ResponseOID.s
		ValueType.w
		Value.s
		Status.w
	EndStructure
	Global MaxStations=50
	Global MaxRequests=100
	Global Dim Station.StationType(MaxStations)
	Global Dim SNMP.SNMPType(MaxRequests)
	Global RequestID.w
; EndDefine
Procedure.l BE_Length(*memory,*pos.Reference)
	; Calculates length of actual field...
	Protected byte
	Protected length
	Protected n
	byte=PeekB(*memory+*pos\Value)
	*pos\Value+1
	If byte&$80;				multi-byte length
		byte&$3;				number of bytes for length information
		While byte
			length<<8
			length+(PeekB(*memory+*pos\Value)&$ff)
			byte-1
			*pos\Value+1
		Wend
	Else
		length=byte&$7f
	EndIf
	;Debug "Len: "+Str(length)
	ProcedureReturn length
EndProcedure
Procedure.l BE_Integer(*memory,length)
	; Encodes memory to integer value...
	Protected n
	While length
		n<<8
		n+(PeekB(*memory)&$ff)
		length-1
		*memory+1
	Wend
	ProcedureReturn n
EndProcedure
Procedure.s BE_Object(*memory,length)
	; Encodes Memory to OID string...
	Protected ID
	Protected OID.s
	Protected byte
	Protected i=0
	While i<length
		byte=PeekB(*memory+i)&$FF
		If ID & $FE000000
			OID+".???"
			Break
		EndIf
		ID<<7
		ID|(byte&$7F)
		If byte&$80=0
			If i
				OID+"."+Str(ID)
			Else
				Select byte
				Case 43
					OID=".1.3"
				Case 0 To 63
					OID=".0"
				Case 64 To 127
					OID=".1.64"
				Default
					OID=".2.128"
				EndSelect
			EndIf
			ID=0
		EndIf
		i+1
	Wend
	ProcedureReturn OID
EndProcedure
Procedure.l BM_Integer(value.l,*memory,*pos.Reference)
	; Writes integer value into memory, starting at position *pos
	; Returns number of used Bytes...
	If (value<$80)
		PokeB(*memory+*pos\Value,value)
		value=1
	Else
		PokeB(*memory+*pos\Value,(value>>8)&$ff)
		PokeB(*memory+*pos\Value+1,value&$ff)
		value=2
	EndIf
	*pos\Value+value
	ProcedureReturn value
EndProcedure
Procedure.l BM_Value(value.l,*memory,*pos.Reference)
	; should use quads, but because of pures poor quad handling limited to long for now ;(
	; Writes integer value into memory, starting at position *pos
	; Returns number of used Bytes...
	If (value>=0) And (value<128)
		PokeB(*memory+*pos\Value,value)
		value=1
	ElseIf  (value>=128) And (value<16384)
		Debug Str(value)+" = "+Str($80|(value>>7))+", "+Str(value&$7f)
		PokeB(*memory+*pos\Value, $80|(value>>7))
		PokeB(*memory+*pos\Value+1, value&$7f)
		value=2
	ElseIf (value>=16384) And (value<2097152)
		PokeB(*memory+*pos\Value, $80|((value>>14)&$7f))
		PokeB(*memory+*pos\Value+1, $80|((value>>7)&$7f))
		PokeB(*memory+*pos\Value+2, value&$7f)
		value=3
	ElseIf (value>=2097152) And (value<268435456)
		PokeB(*memory+*pos\Value, $80|((value>>21)&$7f))
		PokeB(*memory+*pos\Value+1, $80|((value>>14)&$7f))
		PokeB(*memory+*pos\Value+2, $80|((value>>7)&$7f))
		PokeB(*memory+*pos\Value+3, value&$7f)
		value=4
	ElseIf (value>=268435456) And (value<4294967296)
		PokeB(*memory+*pos\Value, $80|((value>>28)&$7f))
		PokeB(*memory+*pos\Value+1, $80|((value>>21)&$7f))
		PokeB(*memory+*pos\Value+2, $80|((value>>14)&$7f))
		PokeB(*memory+*pos\Value+3, $80|((value>>7)&$7f))
		PokeB(*memory+*pos\Value+4, value&$7f)
		value=5
	Else
		value=0
	EndIf
	*pos\Value+value
	ProcedureReturn value
EndProcedure
Procedure.l BM_String(value.s,*memory,*pos.Reference)
	; Writes string value into memory, starting at position *pos
	; Returns number of used Bytes...
	Protected length=Len(value)
	If length
		PokeS(*memory+*pos\Value,value,length)
		*pos\Value+length
	EndIf
	ProcedureReturn length
EndProcedure
Procedure.l BM_Object(OID.s,*memory,*pos.Reference)
	; Writes OID object into memory starting at position *pos
	; Returns number of used bytes
	Protected value
	Protected i,n
	Protected length=0
	If PeekB(@OID)='.'
		OID=PeekS(@OID+1)
	EndIf
	n=CountString(OID,".")
	value=Val(StringField(OID,1,".")) *40 + Val(StringField(OID,2,"."))
	length+BM_Value(value,*memory,*pos)
	If CountString(OID,".") > 1
		For i=3 To n+1
			length+BM_Value(Val(StringField(OID,i,".")),*memory,*pos)
		Next
	EndIf
	ProcedureReturn length
EndProcedure
Procedure.l BM_Move(value.l,length.l,*memory,*pos.Reference)
	; Insert byte value into memory block...
	; Returns total length
	CopyMemory(*memory+*pos\Value-length,*memory+*pos\Value-length+2,length)
	PokeB(*memory+*pos\Value-length,value)
	PokeB(*memory+*pos\Value-length+1,length)
	*pos\Value+2
	ProcedureReturn length+2
EndProcedure
Procedure.l BM_Null(value.l,*memory,*pos.Reference)
	; Writes byte value into memory address...
	; Returns length (=2)
	PokeB(*memory+*pos\Value,value)
	PokeB(*memory+*pos\Value+1,0)
	*pos\Value+2
	ProcedureReturn 2
EndProcedure
Procedure.l Ping(n)
	; Pings Station(n)\IP...
	; Returns #True if a reply packet is seen from the station
	Protected EchoMessage.s
	Protected EchoSize
	Protected *Echo.ICMP_ECHO_REPLY
	Protected *EchoResult
	Protected Handle
	With Station(n)
		\Alive=#Station_Down
		
		EchoMessage.s="Michael Vogel"
		EchoSize.l=SizeOf(ICMP_ECHO_REPLY)+Len(EchoMessage)
		*EchoResult=AllocateMemory(EchoSize)
		*Echo=*EchoResult
		If \IP
			Handle=IcmpCreateFile_()
			If IcmpSendEcho_(Handle,\IP,EchoMessage,Len(EchoMessage),0,*EchoResult,EchoSize,500)
				; Received an ICMP-Response...
				If PeekL(*EchoResult)=\IP
					;...from the destination address (otherwise it will be a destination unreachable message from the default gateway)
					\Alive=#Station_Up
				EndIf
			EndIf
			IcmpCloseHandle_(Handle)
		EndIf
		FreeMemory(*EchoResult)
		ProcedureReturn \Alive
		
	EndWith
	
EndProcedure
Procedure.l PDU_Check(n,*memory)
	Protected byte
	Protected length
	Protected pos
	Protected field
	Protected Value.s
	; Class (Bits 7/8)
	; 0 - Universal (integer, string etc.)
	; 1 - Application (IP address, Time Ticks)
	; 2 - Context (complex data)
	; 3 - Private (non standard data)
	; Data Type (Bit 6)
	; 0 - primitive data-type
	; 1 - constructed data-type
	; ASN.1 Type (Bit 5)
	; 0 - no
	; 1 - yes
	With SNMP(n)
		pos=0
		Repeat
			byte=PeekB(*memory+pos)&$ff
			;Debug "Field: "+Str(field)+"  Pos: "+Str(pos)+" (=$"+Hex(byte&$ff)+")"
			pos+1
			length=BE_Length(*memory,@pos);
			Select byte>>6;						class...
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			Case 0;										universal class
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				If byte&$20;							constructed data type
					If byte&$10;						ASN.1
						;Debug "   Length: "+Str(length)
					EndIf
				Else;										primitive data type
					Select byte&$f
					Case 2
						\ValueType=#TypeInteger
						Value=Str(BE_Integer(*memory+pos,length))
						;Debug "   integer: "+Value
					Case 3
						;Debug "   bit string"
					Case 4
						\ValueType=#TypeString
						Value=PeekS(*memory+pos,length)
						;Debug "   octet string: "+Value
					Case 5
						;Debug "   null"
					Case 6
						\ValueType=#TypeObject
						Value=BE_Object(*memory+pos,length)
						;Debug "   object: "+Value
					Default
						Debug Str(n)+" UNKNOWN TYPE: "+Str(byte)
					EndSelect
					pos+length
				EndIf
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			Case 1;										application
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				If byte&$20=0;						primitive data type
					Select byte&$f
					Case 3;							ticks
						Value=Str(BE_Integer(*memory+pos,length))
						\ValueType=#TypeTicks
					EndSelect
				EndIf
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			Case 2;										context specific
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				If byte&$20;							constructed data type
					If byte=$A2
						; $A2 GetResponse PDU...
					EndIf
				Else;										primitive data type
					Debug Str(n)+" ERROR: Unknown Packet"
					\Status=#SNMP_Error
					field=#Field_Nil
				EndIf
			EndSelect
			; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			Select field
			Case #Field_ErrorState
				If Val(Value)
					\Status=#SNMP_Error_Name
					Debug \Status
					Debug Str(n)+" NAME ERROR: "+Value
					field=#Field_Nil
				EndIf
			Case #Field_RequestID
				If Val(Value)<>\RequestID
					\Status=#SNMP_Error_RID
					Debug Str(n)+" RID ERROR: "+Value+"~"+Value
					field=#Field_Nil
				EndIf
			Case #Field_OID
				\ResponseOID=Value
				If (\GetType=#Get) And (Value<>\OID)
					\Status=#SNMP_Error_OID
					Debug Str(n)+" OID ERROR: "+Value+"~"+\OID
					field=#Field_Nil
				EndIf
			Case #Field_Variable
				SNMP(n)\Value=Value
				\Status=#SNMP_Ok
			EndSelect
			field+1
		Until field>#Field_Variable
		ProcedureReturn \Status
	EndWith
EndProcedure
Procedure.l PDU_Make(n,*memory)
	; compose SNMP packet into reserved memory (548 bytes)
	; n = Request number
	; Returns packet length
	Protected length
	Protected pos
	Protected PositionA,PositionB
	With SNMP(n)
		RequestID+1;Random(65535)
		\RequestID=RequestID
		If \GetType<>#GET_NEXT : \GetType=#GET : EndIf
		; SNMPv1
		length=BM_Value($00,*memory,@pos)
		length=BM_Move($02,length,*memory,@pos)
		; Community
		length=BM_String(Station(\StationNumber)\Community,*memory,@pos)
		length=BM_Move($04,length,*memory,@pos)
		PositionA=pos
		; Request ID
		length=BM_Integer(\RequestID,*memory,@pos)
		length=BM_Move($02,length,*memory,@pos)
		; Error-Status
		length=BM_Value(0,*memory,@pos)
		length=BM_Move($02,length,*memory,@pos)
		; Error-Index
		length=BM_Value(0,*memory,@pos)
		length=BM_Move($02,length,*memory,@pos)
		PositionB=pos
		; OID
		length=BM_Object(\OID,*memory,@pos)
		\OID=BE_Object(*memory+PositionB,length); put normalized OID into database
		length=BM_Move($06,length,*memory,@pos)
		; NULL
		length=BM_Null($05,*memory,@pos)
		; Envelope OID and Null-field (two times)
		length=BM_Move($30,pos-PositionB,*memory,@pos)
		length=BM_Move($30,pos-PositionB,*memory,@pos)
		; Envelope Request-ID, Error Information and OID-Envelope
		length=BM_Move(\GetType,pos-PositionA,*memory,@pos)
		; Envelope all SNMP fields
		length=BM_Move($30,pos,*memory,@pos)
	EndWith
	ProcedureReturn pos
EndProcedure
Procedure.l SNMP_Get(n)
	Protected *pointer
	Protected *Buffer
	Protected Status
	Protected Start
	Protected SockInfo.sockaddr_in
	Protected SockIdent
	With SNMP(n)
		\Value=""
		\ValueType=#TypeUnknown
		\Status=#SNMP_Unknown
		If Station(\StationNumber)\IP
			*pointer=Sockinfo
			sockinfo\sin_family=#AF_INET
			sockinfo\sin_port=htons_(161)
			sockinfo\sin_addr=Station(\StationNumber)\IP
			SockIdent=SOCKET_(#AF_INET,2,0)
			If SockIdent<>#INVALID_SOCKET
				*Buffer=AllocateMemory(#SNMP_MaxPacketSize)
				If *Buffer
					Status=PDU_Make(n,*Buffer)
					If Status
						If  sendto_(SockIdent,*Buffer,Status,0,*pointer,SizeOf(sockaddr_in)) <> #SOCKET_ERROR
							;Status=0
							Start=Date()
							Repeat
								Delay(1)
								Status=recv_(SockIdent,*Buffer,#SNMP_MaxPacketSize,2)
								If Date()-Start>5
									Status=#SOCKET_ERROR
								EndIf
							Until Status<>0
							If Status<>#SOCKET_ERROR
								;ReAllocateMemory(*Buffer,Status)
								Status=PDU_Check(n,*Buffer)
								\Status=Status
							Else
								Status=0
								\Status=#SNMP_Error
							EndIf
						EndIf
					EndIf
					FreeMemory(*Buffer)
				EndIf
			EndIf
		EndIf
	EndWith
	ProcedureReturn Status
EndProcedure
Procedure Main()
	If InitNetwork()
		Station(0)\IP=inet_addr_("172.16.222.222")
		Station(0)\Community="public"
		; *** just for testing ***
		Protected i
		For i=1 To 7
			SNMP(i)\StationNumber=0
			SNMP(i)\OID="1.3.6.1.2.1.1."+Str(i)+".0"
			SNMP(i)\Gettype=#GET
		Next i
		For i=1 To 7
			SNMP(i+7)\StationNumber=0
			SNMP(i+7)\OID=".1.3.6.1.2.1.2.2.1."+Str(i)+".1"
			SNMP(i+7)\Gettype=#GET
		Next i
		If Ping(0)=#Station_Up
			
			; *** brute force, have to be modified ***
			For i=1 To 14
				CreateThread(@SNMP_Get(),i)
			Next i
			Delay(2000)   ;)
			Protected Look.s
			For i=1 To 14
				Look+"[ "+Str(i)+":"+Str(SNMP(i)\Status)+","+Str(SNMP(i)\ValueType)+" ] "+SNMP(i)\Value+#CR$
				Debug "~~~ "+Str(i)+" ~~~"
				Debug Str(SNMP(i)\Status)+" / "+Str(SNMP(i)\ValueType)+" / "+SNMP(i)\ResponseOID
				Debug SNMP(i)\Value
			Next i
			MessageRequester("Results",Look)
		EndIf
	EndIf
EndProcedure
Main()