summaryrefslogtreecommitdiff
path: root/ASNMP/asnmp/pdu.cpp
blob: 68c7c0c2fcd170645d3a246d4aca32b208ef1450 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
/* -*-C++-*- */
// ============================================================================
//
// = LIBRARY
//    asnmp
//
// = FILENAME
//     pdu.cpp
//
// = DESCRIPTION
//  Pdu class implementation. Encapsulation of an SMI Protocol
//  Data Unit (PDU) in C++.
//
// = AUTHOR
//   Peter E Mellquist
//   Michael R MacFaden  mrm@cisco.com - rework & ACE port
// ============================================================================
/*===================================================================
  Copyright (c) 1996
  Hewlett-Packard Company

  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
  Permission to use, copy, modify, distribute and/or sell this software 
  and/or its documentation is hereby granted without fee. User agrees 
  to display the above copyright notice and this license notice in all 
  copies of the software and any documentation of the software. User 
  agrees to assume all liability for the use of the software; Hewlett-Packard 
  makes no representations about the suitability of this software for any 
  purpose. It is provided "AS-IS without warranty of any kind,either express 
  or implied. User hereby grants a royalty-free license to any and all 
  derivatives based upon this software code base. 
=====================================================================*/

#include "asnmp/snmp.h"
#include "asnmp/pdu.h"       // include Pdu class definition

//=====================[ constructor no args ]=========================
Pdu::Pdu( void): vb_count_(0), error_status_(0), error_index_(0), 
validity_(FALSE), request_id_(0), pdu_type_(0), notify_timestamp_(0), 
output_(0)
{
}

//=====================[ constructor with vbs_ and count ]==============
Pdu::Pdu( Vb* pvbs, const int pvb_count): vb_count_(0), error_index_(0), 
validity_(FALSE), request_id_(0), pdu_type_(0), notify_timestamp_(0), 
output_(0)
{
   int z;  // looping variable

   // zero is ok
   if ( pvb_count == 0) {
      validity_ = TRUE;
      return;
   }

   // check for over then max
   if ( pvb_count > MAX_VBS) {
       validity_ = FALSE;
       return;
   }

   // loop through and assign internal vbs_
   for (z = 0;z < pvb_count; z++) {
     validity_ = FALSE;
     ACE_NEW(vbs_[z], Vb( pvbs[z]));
     validity_ = TRUE;
   }

   // assign the vb count
   vb_count_ = pvb_count;

   validity_ = TRUE;
}

//=====================[ constructor with another Pdu instance ]========
Pdu::Pdu( const Pdu &pdu): vb_count_(0), 
error_index_(0), validity_(FALSE), request_id_(0), pdu_type_(0),
notify_timestamp_(0), output_(0)
{
   *this = pdu;
   return;
}

//=====================[ destructor ]====================================
Pdu::~Pdu()
{
  delete_all_vbs();
  delete [] output_;
}
 

//=====================[ assignment to another Pdu object overloaded ]===
Pdu& Pdu::operator=( const Pdu &pdu)
{
   int z;   // looping variable

   // Initialize all mv's
   error_status_ = pdu.error_status_;
   error_index_ = pdu.error_index_;
   request_id_ = pdu.request_id_;
   pdu_type_ = pdu.pdu_type_;
   notify_id_ = pdu.notify_id_;
   notify_timestamp_ = pdu.notify_timestamp_;
   notify_enterprise_ = pdu.notify_enterprise_;
   validity_ = TRUE;

   // free up old vbs_
   for ( z = 0;z < vb_count_; z++)
     delete vbs_[z];
   vb_count_ = 0;

   // check for zero case
   if ( pdu.vb_count_ == 0) {
      return *this;
   }

   // loop through and fill em up
   for (z = 0; z < pdu.vb_count_; z++) {
     validity_ = FALSE;
     ACE_NEW_RETURN(vbs_[z], Vb ( *(pdu.vbs_[z])), *this);
     validity_ = TRUE;
   }

   vb_count_ = pdu.vb_count_;
   return *this;
}

// append operator, appends a string
Pdu& Pdu::operator+=( Vb &vb)
{

  // do we have room?
  if ( vb_count_ + 1 > MAX_VBS)
    return *this;      

  // add the new one
  validity_ = FALSE;
  ACE_NEW_RETURN(vbs_[vb_count_], Vb (vb), *this);
  // set up validity_
  validity_ = TRUE;

  // up the vb count
  vb_count_++;

  // return self reference
  return *this;

}

// return fomatted version of this object
char * Pdu::to_string()
{
  // determine how big a buffer and allocate it
  const int HEADER_STR = 100;
  unsigned size = HEADER_STR; // header takes up this much room
  int z;

   for ( z = 0; z < vb_count_; z++) 
       size += ACE_OS::strlen(vbs_[z]->to_string());

  ACE_NEW_RETURN(output_, char[size], "");

  // print pdu header info
  sprintf(output_, "pdu: valid: %d type:%d, req:%d, cnt: %d, err stat: %d \
 err idx: %d\n",     validity_, pdu_type_, (int) request_id_,
    vb_count_, error_status_, error_index_ );

  // now append vb pairs in this object
   for ( z = 0; z < vb_count_; z++) {
     ACE_OS::strcat(output_, vbs_[z]->to_string());
     ACE_OS::strcat(output_, "\n\t");
   }

  return output_;
}
 

//=====================[ extract Vbs from Pdu ]==========================
// how do you know that the caler has enough memory???
// should I self allocate this in here and require the
// caller then to free it up at soem later time
int Pdu::get_vblist( Vb* pvbs, const int pvb_count)
{
   if ((!pvbs) || ( pvb_count < 0) || ( pvb_count > vb_count_))
      return FALSE;

   // loop through all vbs_ and assign to params
   int z;
   for (z = 0; z < pvb_count; z++)
      pvbs[z] = *vbs_[z];

   return TRUE;

}

//=====================[ deposit Vbs ]===================================
int Pdu::set_vblist( Vb* pvbs, const int pvb_count)
{

   // if invalid then don't destroy
   if ((!pvbs) || ( pvb_count < 0) || ( pvb_count > MAX_VBS))
     return FALSE;

   // free up current vbs_
   int z;
   for ( z = 0; z < vb_count_; z++)
     delete vbs_[z];
   vb_count_ = 0;

   // check for zero case
   if ( pvb_count == 0) {  
      validity_ = TRUE;
      error_status_ = 0;
      error_index_ = 0;
      request_id_ = 0;
      return FALSE;
   }
     

   // loop through all vbs_ and reassign them
   for ( z = 0; z < pvb_count; z++) {
     validity_ = FALSE;
     ACE_NEW_RETURN(vbs_[z], Vb (pvbs[z]), FALSE);
     validity_ = TRUE;
   }
   
   vb_count_ = pvb_count;

   // clear error status and index since no longer valid
   // request id may still apply so don't reassign it
   error_status_ = 0;
   error_index_ = 0;
   validity_ = TRUE;

   return TRUE;
}

//===================[ get a particular vb ]=============================
// here the caller has already instantiated a vb object
// index is zero based
int Pdu::get_vb( Vb &vb, const int index) const
{
   // can't have an index less than 0
   if ( index < 0) 
     return FALSE;

   // can't ask for something not there
   if ( index > (vb_count_ - 1))
      return FALSE;

   // asssign it
   vb = *vbs_[index];

   return TRUE;
}

//===================[ set a particular vb ]=============================
int Pdu::set_vb( Vb &vb, const int index)
{
   // can't set a vb at index less than 0
   if ( index < 0)
     return FALSE;

   // can't ask for something not there
   if ( index > (vb_count_ - 1))
      return FALSE;

   // delete what is there
   delete vbs_[index];

   // assign it
   validity_ = FALSE;
   ACE_NEW_RETURN(vbs_[index], Vb (vb), FALSE);
   validity_ = TRUE;

   return TRUE;

}

//=====================[ return number of vbs_ ]==========================
int Pdu::get_vb_count() const
{
   return vb_count_;
}

//=====================[ return the error status ]=======================
int Pdu::get_error_status() const
{
   return error_status_;
}

char *Pdu::agent_error_reason()
{
    int pdu_err = get_error_status();
    if (pdu_err == 0) // any real error?
        return "not in error state";
    
    int n_vbs = get_vb_count();
    Vb bad;
    get_vb(bad, get_error_index() -1); // not zero based??
    char *pmsg =   Snmp::error_string(get_error_status());
    char *id =   bad.to_string_oid();
    char *val =  bad.to_string_value();
    const int HDR_SZ = 100;

    if (!output_) {
      int size = ACE_OS::strlen(pmsg) + ACE_OS::strlen(id) + 
           ACE_OS::strlen(val);
      ACE_NEW_RETURN(output_, char[size + HDR_SZ], "");
    }

    ACE_OS::sprintf(output_, 
"FAIL PDU REPORT: pdu id: %d vb cnt: %d vb idx: %d \n\
msg: %s vb oid: %s value: %s",
      get_request_id(), n_vbs, get_error_index(),  pmsg, id, val); 

    return output_;
}

//=====================[ set the error status ]==========================
// friend
void set_error_status( Pdu *pdu, const int status)
{
   if (pdu)
     pdu->error_status_ = status;
}

//=====================[ return the error index ]========================
int Pdu::get_error_index() const
{
   return error_index_;
}

//=====================[ set the error index ]===========================
// friend
void set_error_index( Pdu *pdu, const int index)
{
   if (pdu)
     pdu->error_index_ = index;
}

//=====================[ clear error status ]=============================
void clear_error_status( Pdu *pdu)
{
   if (pdu)
     pdu->error_status_ = 0;
}

//=====================[ clear error index ]==============================
void clear_error_index( Pdu *pdu)
{
   if (pdu)
     pdu->error_index_ = 0;
}

//=====================[ return the request id ]==========================
unsigned long Pdu::get_request_id() const
{
   return request_id_;
}

//=====================[ set the request id ]=============================
// friend function
void set_request_id( Pdu *pdu, const unsigned long rid)
{
   if (pdu)
     pdu->request_id_ = rid;
}

//=====================[ returns validity_ of Pdu instance ]===============
int Pdu::valid() const 
{
   return validity_;
}

//=====================[ get the pdu type ]===============================
unsigned short Pdu::get_type()const
{
   return pdu_type_;
}

// set the pdu type
void Pdu::set_type( unsigned short type)
{
   pdu_type_ = type;
}


// trim off the last vb
int Pdu::trim(const int p)
{
   int lp = p;

   // verify that lp is legal
   if ( lp < 0 || lp > vb_count_)
     return FALSE;

   while ( lp != 0)   {
     if ( vb_count_ > 0) {
         delete vbs_[vb_count_ - 1];
         vb_count_--;
     }
     lp--;
   }
   return TRUE;
}



// delete a Vb anywhere within the Pdu
int Pdu::delete_vb( const int p)
{
   // position has to be in range
   if (( p < 0) || ( p > (vb_count_ - 1)))
      return FALSE;

   // safe to remove it
   delete vbs_[ p];

   for ( int z=p;z < (vb_count_-1);z++) {
      vbs_[z] = vbs_[z+1];
   }  
   vb_count_--;

   return TRUE;
}

void Pdu::delete_all_vbs()
{
  for ( int z = 0; z < vb_count_; z++)
     delete vbs_[z];
   vb_count_ = 0;
}


// set notify timestamp
void Pdu::set_notify_timestamp( const TimeTicks & timestamp)
{
   notify_timestamp_ = timestamp;
}


// get notify timestamp
void Pdu::get_notify_timestamp( TimeTicks & timestamp) const
{
    timestamp = notify_timestamp_;
}

// set the notify id
void Pdu::set_notify_id( const Oid id)
{
    notify_id_ = id;
}

// get the notify id
void Pdu::get_notify_id( Oid &id) const
{
   id = notify_id_;
}

// set the notify enterprise
void Pdu::set_notify_enterprise( const Oid &enterprise)
{
   notify_enterprise_ = enterprise;
}

// get the notify enterprise
void Pdu::get_notify_enterprise( Oid & enterprise) const
{
    enterprise = notify_enterprise_;
}

// ------   class VbIter -------------------
VbIter::VbIter(Pdu& pdu): idx_(-1), pdu_(&pdu)
{
}

// returns 1 if ok, else 0 if none left
int VbIter::next(Vb& vb)
{
   if (idx_ == -1) {
    idx_ = 0;
    pdu_->get_vb(vb, idx_++);
    return 1;
   }
  else
  if (idx_ < pdu_->get_vb_count()) {
    pdu_->get_vb(vb, idx_++);
    return 1;
  }
  return 0; // non left
}