AgentXcpp  Revision:0.1.1
Internals Documentation
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Pages
oid.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2012 Tanjeff-Nicolai Moos <tanjeff@cccmz.de>
3  *
4  * This file is part of the agentXcpp library.
5  *
6  * AgentXcpp is free software: you can redistribute it and/or modify
7  * it under the terms of the AgentXcpp library license, version 1, which
8  * consists of the GNU General Public License and some additional
9  * permissions.
10  *
11  * AgentXcpp is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * See the AgentXcpp library license in the LICENSE file of this package
17  * for more details.
18  */
19 
20 //#include <iostream>
21 #include <sstream>
22 #include "oid.hpp"
23 #include "exceptions.hpp"
24 
25 
26 using namespace agentxcpp;
27 using namespace std;
28 
29 
30 void oid::parse_string(std::string s)
31 {
32  // Do not parse empty string
33  if(s.empty()) return;
34 
35  // Parse the string
36  std::istringstream ss(s);
37  uint32_t subid;
38  char ch;
39  while(ss)
40  {
41  // Read a subid
42  ss >> subid;
43  if(!ss)
44  {
45  // cannot get number: parse error
46  // This happens also if the number is too large
47  throw( inval_param() );
48  }
49  push_back(subid);
50 
51  // Read a period
52  ss >> ch;
53  if(!ss)
54  {
55  // end of string: end of parsing
56  break;
57  }
58  if(ch != '.')
59  {
60  // Wrong char: parse error
61  throw( inval_param() );
62  }
63  }
64 }
65 
66 
67 
68 oid::oid(std::string s)
69 {
70  include = false;
71 
72  // parse the string. Forward all exceptions.
73  parse_string(s);
74 }
75 
76 
77 oid::oid(const oid& o, std::string id)
78 {
79  // start with o
80  *this = o;
81 
82  // add OID from string. Forward all exceptions.
83  parse_string(id);
84 }
85 
86 
87 std::ostream& agentxcpp::operator<<(std::ostream& out, const oid& o)
88 {
89  // Leading dot
90  out << ".";
91 
92  // If no subidentifiers are present, we are done
93  if(o.size() == 0)
94  {
95  return out;
96  }
97 
98  // Get iterator to first subidentifier
99  oid::const_iterator it = o.begin();
100 
101  // Print first subidentifier
102  out << *it;
103  it++;
104 
105  // Output remaining subidentifiers, each prepended with a dot
106  while(it != o.end())
107  {
108  out << "." << *it;
109  it++;
110  }
111 
112  // Done, return
113  return out;
114 }
115 
116 
117 
119 {
120  // The serial representation of an OID is as follows (RFC 2741, section
121  // 5.1):
122  //
123  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124  // | n_subid | prefix | include | <reserved> |
125  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126  // | sub-identifier #1 |
127  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
128  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
129  // | sub-identifier #n_subid |
130  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131  //
132  // We use a string here to represent the serial stream, and we use some
133  // constants as indexes:
134  const int n_subid_idx = 0;
135  const int prefix_idx = 1;
136  const int include_idx = 2;
137  const int reserved_idx = 3;
138 
139  // This is our binary data:
140  binary serialized;
141  serialized.resize(4); // we will need at least the header
142 
143  // Set reserved field to 0
144  serialized[reserved_idx] = 0;
145 
146  // Set include field
147  serialized[include_idx] = include ? 1 : 0;
148 
149  // Iterator for the subid's
150  oid::const_iterator subid = this->begin();
151 
152  // Check whether we can use the prefix (RFC 2741, section 5.1)
153  if( this->size() >= 5 &&
154  (*this)[0] == 1 &&
155  (*this)[1] == 3 &&
156  (*this)[2] == 6 &&
157  (*this)[3] == 1 &&
158  (*this)[4] <= 0xff) // we have only one byte for the prefix!
159  {
160  // store the first integer after 1.3.6.1 to prefix field
161  serialized[prefix_idx] = (*this)[4];
162  subid += 5; // point to the subid behind prefix
163 
164  // 5 elements are represented by prefix
165  serialized[n_subid_idx] = this->size() - 5;
166  }
167  else
168  {
169  // don't use prefix field
170  serialized[prefix_idx] = 0;
171 
172  // All subid's are stored in the stream explicitly
173  serialized[n_subid_idx] = this->size();
174  }
175 
176  // copy subids to serialized
177  while( subid != this->end() )
178  {
179  serialized.push_back( (*subid) << 24 & 0xff );
180  serialized.push_back( (*subid) << 16 & 0xff );
181  serialized.push_back( (*subid) << 8 & 0xff );
182  serialized.push_back( (*subid) << 0 & 0xff );
183  subid++;
184  }
185 
186  return serialized;
187 }
188 
189 oid::oid(binary::const_iterator& pos,
190  const binary::const_iterator& end,
191  bool big_endian)
192 {
193  if(end - pos < 4)
194  {
195  throw(parse_error());
196  }
197 
198  // get number of subid's
199  int n_subid = *pos++;
200 
201  // parse prefix
202  int prefix = *pos++;
203  if( prefix != 0 )
204  {
205  this->push_back(1);
206  this->push_back(3);
207  this->push_back(6);
208  this->push_back(1);
209  this->push_back(prefix);
210  }
211 
212  // parse include field
213  switch( *pos++ )
214  {
215  case 0:
216  include = false;
217  break;
218  case 1:
219  include = true;
220  break;
221  default:
222  // Invalid value; we are picky and indicate an error:
223  throw parse_error();
224  }
225 
226  // skip reserved field
227  *pos++;
228 
229  // parse rest of data, subid by subid
230  if(end - pos < n_subid * 4)
231  {
232  throw(parse_error());
233  }
234  uint32_t subid;
235  for( int i = 0; i < n_subid; i++)
236  {
237  if(big_endian)
238  {
239  // big endian
240  subid = *pos++ << 24;
241  subid |= *pos++ << 16;
242  subid |= *pos++ << 8;
243  subid |= *pos++ << 0;
244  }
245  else
246  {
247  // little posdian
248  subid = *pos++ << 0;
249  subid |= *pos++ << 8;
250  subid |= *pos++ << 16;
251  subid |= *pos++ << 24;
252  }
253  this->push_back(subid);
254  }
255 }
256 
257 
258 bool oid::operator<(const oid& o) const
259 {
260  oid::const_iterator mine, yours;
261  mine = this->begin();
262  yours = o.begin();
263 
264  // Test as many parts as the shorter OID has:
265  while( mine != this->end()
266  && yours != o.end() )
267  {
268  if( *mine < *yours )
269  {
270  // my oid part is less than yours
271  return true;
272  }
273  if( *mine > *yours )
274  {
275  // my oid part is greater than yours
276  return false;
277  }
278 
279  // our parts are identical; test next part:
280  mine++;
281  yours++;
282  }
283 
284  // Ok, either you and I have different length (where the one with fewer
285  // parts is less than the other) or we have the same number of parts (in
286  // which case we are identical).
287  if( this->size() < o.size() )
288  {
289  // I have less parts than you, so I am less than you:
290  return true;
291  }
292  else
293  {
294  // I have not less parts than you:
295  return false;
296  }
297 }
298 
299 
300 
301 bool oid::operator==(const oid& o) const
302 {
303  // Quick test: if the oids have different number of parts, they are not
304  // equal:
305  if( this->size() != o.size() )
306  {
307  return false;
308  }
309 
310  // Test all parts:
311  oid::const_iterator mine, yours;
312  mine = this->begin();
313  yours = o.begin();
314 
315  while( mine != this->end()
316  && yours != o.end() )
317  {
318  if( *mine != *yours )
319  {
320  // The parts differ: OIDs not equal
321  return false;
322  }
323 
324  // Parts are equal, test next parts
325  mine++;
326  yours++;
327  }
328 
329  // All parts tested and all parts were equal. Further both OIDs have the
330  // same number of parts, thus they are equal.
331  return true;
332 }
333 
334 
335 oid& oid::operator=(const oid& other)
336 {
337  // copy our own members
338  this->include = other.include;
339 
340  // copy inherited stuff
341  vector<uint32_t>::operator=(other);
342  variable::operator=(other);
343 
344  // Return reference to us
345  return *this;
346 }
347 
348 
349 bool oid::contains(const oid& id)
350 {
351  // If id has fewer subids than this: not contained
352  if(this->size() > id.size())
353  {
354  // Is not contained
355  return false;
356  }
357 
358  // id has at least as many subids than this -> iteration is safe
359  for(size_type i = 0; i < this->size(); i++)
360  {
361  if( (*this)[i] != id[i] )
362  {
363  // We differ in a subid!
364  return false;
365  }
366  }
367 
368  // If we get here, the id starts the same subids as this (it has possibly
369  // more subids). This means that it is contained in the subtree spanned by
370  // this.
371  return true;
372 }
373 
374 
375 bool oid::is_null() const
376 {
377  if( this->size() == 0 &&
378  ! this->include)
379  {
380  // Is the null OID
381  return true;
382  }
383  else
384  {
385  return false;
386  }
387 }