AgentXcpp  Revision:0.1
Internals Documentation
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends
/home/tanjeff/projekte/agentxcpp/src/oid.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2011-2012 Tanjeff-Nicolai Moos <tanjeff@cccmz.de>
00003  *
00004  * This file is part of the agentXcpp library.
00005  *
00006  * AgentXcpp is free software: you can redistribute it and/or modify
00007  * it under the terms of the AgentXcpp library license, version 1, which 
00008  * consists of the GNU General Public License and some additional 
00009  * permissions.
00010  *
00011  * AgentXcpp is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * See the AgentXcpp library license in the LICENSE file of this package 
00017  * for more details.
00018  */
00019 
00020 //#include <iostream>
00021 #include <sstream>
00022 #include "oid.hpp"
00023 #include "exceptions.hpp"
00024 
00025 
00026 using namespace agentxcpp;
00027 using namespace std;
00028 
00029 
00030 void oid::parse_string(std::string s)
00031 {
00032     // Do not parse empty string
00033     if(s.empty()) return;
00034 
00035     // Parse the string
00036     std::istringstream ss(s);
00037     uint32_t subid;
00038     char ch;
00039     while(ss)
00040     {
00041         // Read a subid
00042         ss >> subid;
00043         if(!ss)
00044         {
00045             // cannot get number: parse error
00046             // This happens also if the number is too large
00047             throw( inval_param() );
00048         }
00049         push_back(subid);
00050 
00051         // Read a period
00052         ss >> ch;
00053         if(!ss)
00054         {
00055             // end of string: end of parsing
00056             break;
00057         }
00058         if(ch != '.')
00059         {
00060             // Wrong char: parse error
00061             throw( inval_param() );
00062         }
00063     }
00064 }
00065 
00066 
00067 
00068 oid::oid(std::string s)
00069 {
00070     include = false;
00071 
00072     // parse the string. Forward all exceptions.
00073     parse_string(s);
00074 }
00075 
00076 
00077 oid::oid(const oid& o, std::string id)
00078 {
00079     // start with o
00080     *this = o;
00081 
00082     // add OID from string. Forward all exceptions.
00083     parse_string(id);
00084 }
00085 
00086 
00087 std::ostream& agentxcpp::operator<<(std::ostream& out, const oid& o)
00088 {
00089     // Leading dot
00090     out << ".";
00091 
00092     // If no subidentifiers are present, we are done
00093     if(o.size() == 0)
00094     {
00095         return out;
00096     }
00097 
00098     // Get iterator to first subidentifier
00099     oid::const_iterator it = o.begin();
00100 
00101     // Print first subidentifier
00102     out << *it;
00103     it++;
00104 
00105     // Output remaining subidentifiers, each prepended with a dot
00106     while(it != o.end())
00107     {
00108         out << "." << *it;
00109         it++;
00110     }
00111 
00112     // Done, return
00113     return out;
00114 }
00115 
00116 
00117 
00118 data_t oid::serialize() const
00119 {
00120     // The serial representation of an OID is as follows (RFC 2741, section 
00121     // 5.1):
00122     //
00123     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00124     // |  n_subid      |  prefix       |  include      |  <reserved>   |
00125     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00126     // |                       sub-identifier #1                       |
00127     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00128     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00129     // |                       sub-identifier #n_subid                 |
00130     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00131     //
00132     // We use a string here to represent the serial stream, and we use some 
00133     // constants as indexes:
00134     const int n_subid_idx = 0;
00135     const int prefix_idx = 1;
00136     const int include_idx = 2;
00137     const int reserved_idx = 3;
00138 
00139     // This is our binary data:
00140     data_t serialized;
00141     serialized.resize(4);       // we will need at least the header
00142 
00143     // Set reserved field to 0
00144     serialized[reserved_idx] = 0;
00145 
00146     // Set include field
00147     serialized[include_idx] = include ? 1 : 0;
00148 
00149     // Iterator for the subid's
00150     oid::const_iterator subid = this->begin();
00151 
00152     // Check whether we can use the prefix (RFC 2741, section 5.1)
00153     if( this->size() >= 5 &&
00154         (*this)[0] == 1 &&
00155         (*this)[1] == 3 &&
00156         (*this)[2] == 6 &&
00157         (*this)[3] == 1 &&
00158         (*this)[4] <= 0xff)     // we have only one byte for the prefix!
00159     {
00160         // store the first integer after 1.3.6.1 to prefix field
00161         serialized[prefix_idx] = (*this)[4];
00162         subid += 5; // point to the subid behind prefix
00163 
00164         // 5 elements are represented by prefix
00165         serialized[n_subid_idx] = this->size() - 5;
00166     }
00167     else
00168     {
00169         // don't use prefix field
00170         serialized[prefix_idx] = 0;
00171 
00172         // All subid's are stored in the stream explicitly
00173         serialized[n_subid_idx] = this->size();
00174     }
00175 
00176     // copy subids to serialized
00177     while( subid != this->end() )
00178     {
00179         serialized.push_back( (*subid) << 24 & 0xff );
00180         serialized.push_back( (*subid) << 16 & 0xff );
00181         serialized.push_back( (*subid) << 8 & 0xff );
00182         serialized.push_back( (*subid) << 0 & 0xff );
00183         subid++;
00184     }
00185 
00186     return serialized;
00187 }
00188 
00189 oid::oid(data_t::const_iterator& pos,
00190          const data_t::const_iterator& end,
00191          bool big_endian)
00192 {
00193     if(end - pos < 4)
00194     {
00195         throw(parse_error());
00196     }
00197     
00198     // get number of subid's
00199     int n_subid = *pos++;
00200 
00201     // parse prefix
00202     int prefix = *pos++;
00203     if( prefix != 0 )
00204     {
00205         this->push_back(1);
00206         this->push_back(3);
00207         this->push_back(6);
00208         this->push_back(1);
00209         this->push_back(prefix);
00210     }
00211 
00212     // parse include field
00213     switch( *pos++ )
00214     {
00215         case 0:
00216             include = false;
00217             break;
00218         case 1:
00219             include = true;
00220             break;
00221         default:
00222             // Invalid value; we are picky and indicate an error:
00223             throw parse_error();
00224     }
00225 
00226     // skip reserved field
00227     *pos++;
00228 
00229     // parse rest of data, subid by subid
00230     if(end - pos < n_subid * 4)
00231     {
00232         throw(parse_error());
00233     }
00234     uint32_t subid;
00235     for( int i = 0; i < n_subid; i++)
00236     {
00237         if(big_endian)
00238         {
00239             // big endian
00240             subid =  *pos++ << 24;
00241             subid |= *pos++ << 16;
00242             subid |= *pos++ << 8;
00243             subid |= *pos++ << 0;
00244         }
00245         else
00246         {
00247             // little posdian
00248             subid =  *pos++ << 0;
00249             subid |= *pos++ << 8;
00250             subid |= *pos++ << 16;
00251             subid |= *pos++ << 24;
00252         }
00253         this->push_back(subid);
00254     }
00255 }
00256 
00257 
00258 bool oid::operator<(const oid& o) const
00259 {
00260     oid::const_iterator mine, yours;
00261     mine = this->begin();
00262     yours = o.begin();
00263 
00264     // Test as many parts as the shorter OID has:
00265     while( mine != this->end()
00266             && yours != o.end() )
00267     {
00268         if( *mine < *yours )
00269         {
00270             // my oid part is less than yours
00271             return true;
00272         }
00273         if( *mine > *yours )
00274         {
00275             // my oid part is greater than yours
00276             return false;
00277         }
00278 
00279         // our parts are identical; test next part:
00280         mine++;
00281         yours++;
00282     }
00283 
00284     // Ok, either you and I have different length (where the one with fewer 
00285     // parts is less than the other) or we have the same number of parts (in 
00286     // which case we are identical).
00287     if( this->size() < o.size() )
00288     {
00289         // I have less parts than you, so I am less than you:
00290         return true;
00291     }
00292     else
00293     {
00294         // I have not less parts than you:
00295         return false;
00296     }
00297 }
00298 
00299 
00300 
00301 bool oid::operator==(const oid& o) const
00302 {
00303     // Quick test: if the oids have different number of parts, they are not 
00304     // equal:
00305     if( this->size() != o.size() )
00306     {
00307         return false;
00308     }
00309     
00310     // Test all parts:
00311     oid::const_iterator mine, yours;
00312     mine = this->begin();
00313     yours = o.begin();
00314 
00315     while( mine != this->end()
00316             && yours != o.end() )
00317     {
00318         if( *mine != *yours )
00319         {
00320             // The parts differ: OIDs not equal
00321             return false;
00322         }
00323 
00324         // Parts are equal, test next parts
00325         mine++;
00326         yours++;
00327     }
00328 
00329     // All parts tested and all parts were equal. Further both OIDs have the 
00330     // same number of parts, thus they are equal.
00331     return true;
00332 }
00333 
00334 
00335 oid& oid::operator=(const oid& other)
00336 {
00337     // copy our own members
00338     this->include = other.include;
00339 
00340     // copy inherited stuff
00341     vector<uint32_t>::operator=(other);
00342     variable::operator=(other);
00343     
00344     // Return reference to us
00345     return *this;
00346 }
00347 
00348 
00349 bool oid::contains(const oid& id)
00350 {
00351     // If id has fewer subids than this: not contained
00352     if(this->size() > id.size())
00353     {
00354         // Is not contained
00355         return false;
00356     }
00357 
00358     // id has at least as many subids than this -> iteration is safe
00359     for(size_type i = 0; i < this->size(); i++)
00360     {
00361         if( (*this)[i] != id[i] )
00362         {
00363             // We differ in a subid!
00364             return false;
00365         }
00366     }
00367 
00368     // If we get here, the id starts the same subids as this (it has possibly 
00369     // more subids). This means that it is contained in the subtree spanned by 
00370     // this.
00371     return true;
00372 }
00373 
00374 
00375 bool oid::is_null() const
00376 {
00377     if( this->size() == 0 &&
00378         ! this->include)
00379     {
00380         // Is the null OID
00381         return true;
00382     }
00383     else
00384     {
00385         return false;
00386     }
00387 }