]> git.stg.codes - ssmd.git/blob - 3rdparty/snmp++/src/address.cpp
Initial adding
[ssmd.git] / 3rdparty / snmp++ / src / address.cpp
1 /*_############################################################################
2   _## 
3   _##  address.cpp  
4   _##
5   _##  SNMP++v3.2.25
6   _##  -----------------------------------------------
7   _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
8   _##
9   _##  This software is based on SNMP++2.6 from Hewlett Packard:
10   _##  
11   _##    Copyright (c) 1996
12   _##    Hewlett-Packard Company
13   _##  
14   _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
15   _##  Permission to use, copy, modify, distribute and/or sell this software 
16   _##  and/or its documentation is hereby granted without fee. User agrees 
17   _##  to display the above copyright notice and this license notice in all 
18   _##  copies of the software and any documentation of the software. User 
19   _##  agrees to assume all liability for the use of the software; 
20   _##  Hewlett-Packard and Jochen Katz make no representations about the 
21   _##  suitability of this software for any purpose. It is provided 
22   _##  "AS-IS" without warranty of any kind, either express or implied. User 
23   _##  hereby grants a royalty-free license to any and all derivatives based
24   _##  upon this software code base. 
25   _##  
26   _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
27   _##  
28   _##########################################################################*/
29 /*===================================================================
30
31   Copyright (c) 1999
32   Hewlett-Packard Company
33
34   ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
35   Permission to use, copy, modify, distribute and/or sell this software
36   and/or its documentation is hereby granted without fee. User agrees
37   to display the above copyright notice and this license notice in all
38   copies of the software and any documentation of the software. User
39   agrees to assume all liability for the use of the software; Hewlett-Packard
40   makes no representations about the suitability of this software for any
41   purpose. It is provided "AS-IS" without warranty of any kind,either express
42   or implied. User hereby grants a royalty-free license to any and all
43   derivatives based upon this software code base.
44
45   A D D R E S S. C P P
46
47   ADDRESS CLASS IMPLEMENTATION
48
49   DESIGN + AUTHOR:  Peter E. Mellquist
50
51   DESCRIPTION:      Implementation file for Address classes.
52 =====================================================================*/
53 char address_cpp_version[]="@(#) SNMP++ $Id: address.cpp 1711 2010-02-10 21:25:47Z katz $";
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <ctype.h>
58
59 #if defined(__APPLE__)
60 #include <arpa/inet.h>
61 #include <netdb.h>
62 #endif
63
64 #include "snmp_pp/address.h"
65 #include "snmp_pp/v3.h"
66 #include "snmp_pp/IPv6Utility.h"
67
68 #ifdef SNMP_PP_NAMESPACE
69 namespace Snmp_pp {
70 #endif
71
72 /* Borlands isdigit has a bug */
73 #ifdef __BCPLUSPLUS__
74 #define my_isdigit(c) ((c) >= '0' && (c) <= '9')
75 #else
76 #define my_isdigit isdigit
77 #endif
78
79 #ifdef ADDRESS_DEBUG
80 #define ADDRESS_TRACE debugprintf(0, "ADDRESS %p Enter %s", this, __PRETTY_FUNCTION__)
81 #define ADDRESS_TRACE2 debugprintf(0, "ADDRESS op Enter %s", __PRETTY_FUNCTION__)
82 #else
83 #define ADDRESS_TRACE
84 #define ADDRESS_TRACE2
85 #endif
86
87 #if !defined HAVE_GETHOSTBYNAME_R || !defined HAVE_GETHOSTBYADDR_R || !defined HAVE_REENTRANT_GETHOSTBYNAME || !defined HAVE_REENTRANT_GETHOSTBYADDR
88 #ifdef _THREADS
89 SnmpSynchronized Address::syscall_mutex;
90 #endif
91 #endif
92
93 //=================================================================
94 //======== Abstract Address Class Implementation ==================
95 //=================================================================
96
97 Address::Address()
98   : addr_changed(true), valid_flag(false)
99 {
100   ADDRESS_TRACE;
101
102   memset(address_buffer, 0, sizeof(unsigned char)*ADDRBUF);
103 }
104
105 //------------[ Address::trim_white_space( char * ptr) ]------------
106 // destructive trim white space
107 void Address::trim_white_space(char *ptr)
108 {
109   ADDRESS_TRACE;
110
111   char *tmp = ptr;                               // init
112   while (*tmp==' ') tmp++;                       // skip leading white space
113   while (*tmp && (*tmp != ' ')) *ptr++ = *tmp++; // move string to beginning
114   *ptr = 0;                                      // set end of string
115 }
116
117 // Reset the object
118 void Address::clear()
119 {
120   addr_changed = true;
121   valid_flag = false;
122   memset(address_buffer, 0, sizeof(unsigned char)*ADDRBUF);
123 }
124
125 //-----------------------------------------------------------------------
126 // overloaded equivlence operator, are two addresses equal?
127 int operator==(const Address &lhs, const Address &rhs)
128 {
129   ADDRESS_TRACE2;
130
131   return (strcmp((const char*)lhs, (const char*)rhs) == 0);
132 }
133
134 //------------------------------------------------------------------
135 // overloaded > operator, is a1 > a2
136 int operator>(const Address &lhs, const Address &rhs)
137 {
138   ADDRESS_TRACE2;
139
140   return (strcmp((const char*)lhs, (const char*)rhs) > 0);
141 }
142
143 //-----------------------------------------------------------------
144 // overloaded < operator, is a1 < a2
145 int operator<(const Address &lhs, const Address &rhs)
146 {
147   ADDRESS_TRACE2;
148
149   return (strcmp((const char*)lhs, (const char*)rhs) < 0);
150 }
151
152 //------------------------------------------------------------------
153 // equivlence operator overloaded, are an address and a string equal?
154 int operator==(const Address &lhs, const char *rhs)
155 {
156   ADDRESS_TRACE2;
157
158   if (!rhs && !lhs.valid())
159     return TRUE;
160   if (strcmp((const char *)lhs, rhs) == 0)
161     return TRUE;
162   return FALSE;
163 }
164
165 //------------------------------------------------------------------
166 // overloaded > , is a > inaddr
167 int operator>(const Address &lhs, const char *rhs)
168 {
169   ADDRESS_TRACE2;
170
171   if (!rhs)
172     return lhs.valid();  // if lhs valid then > NULL, else invalid !> NULL
173   if (strcmp((const char *)lhs, rhs) > 0)
174     return TRUE;
175   return FALSE;
176 }
177
178 //------------------------------------------------------------------
179 // overloaded >= , is a >= inaddr
180 int operator>=(const Address &lhs, const char *rhs)
181 {
182   ADDRESS_TRACE2;
183
184   if (!rhs)
185     return TRUE; // always >= NULL
186   if (strcmp((const char *)lhs, rhs) >= 0)
187     return TRUE;
188   return FALSE;
189 }
190
191 //-----------------------------------------------------------------
192 // overloaded < , are an address and a string equal?
193 int operator<(const Address &lhs, const char *rhs)
194 {
195   ADDRESS_TRACE2;
196
197   if (!rhs)
198     return FALSE; // always >= NULL
199   if (strcmp((const char *)lhs, rhs) < 0)
200     return TRUE;
201   return FALSE;
202 }
203
204 //-----------------------------------------------------------------
205 // overloaded <= , is a <= inaddr
206 int operator<=(const Address &lhs, const char *rhs)
207 {
208   ADDRESS_TRACE2;
209
210   if (!rhs)
211     return !lhs.valid(); // invalid == NULL, else valid > NULL
212   if (strcmp((const char *)lhs, rhs) <= 0)
213     return TRUE;
214   return FALSE;
215 }
216
217 //=====================================================================
218 //============ IPAddress Implementation ===============================
219 //=====================================================================
220
221 //-------[ construct an IP address with no agrs ]----------------------
222 IpAddress::IpAddress()
223   : Address(), iv_friendly_name_status(0), ip_version(version_ipv4)
224 {
225   ADDRESS_TRACE;
226
227   // always initialize what type this object is
228   smival.syntax = sNMP_SYNTAX_IPADDR;
229   smival.value.string.len = IPLEN;
230   smival.value.string.ptr = address_buffer;
231
232   memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
233 }
234
235 //-------[ construct an IP address with a string ]---------------------
236 IpAddress::IpAddress(const char *inaddr)
237   : Address()
238 {
239   ADDRESS_TRACE;
240
241   // always initialize what type this object is
242   smival.syntax = sNMP_SYNTAX_IPADDR;
243   smival.value.string.len = IPLEN;
244   smival.value.string.ptr = address_buffer;
245
246   // parse_address initializes valid, address_buffer & iv_friendly_name
247   valid_flag = parse_address(inaddr);
248 }
249
250 //-----[ IP Address copy constructor ]---------------------------------
251 IpAddress::IpAddress(const IpAddress &ipaddr)
252     : iv_friendly_name_status(0), ip_version(ipaddr.ip_version),
253       have_ipv6_scope(ipaddr.have_ipv6_scope)
254 {
255   ADDRESS_TRACE;
256
257   // always initialize what type this object is
258   smival.syntax = sNMP_SYNTAX_IPADDR;
259   smival.value.string.len = ipaddr.smival.value.string.len;
260   smival.value.string.ptr = address_buffer;
261
262   memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
263   valid_flag = ipaddr.valid_flag;
264   if (valid_flag)
265   {
266     // copy the address data
267     MEMCPY(address_buffer, ipaddr.address_buffer, smival.value.string.len);
268     // and the friendly name
269     strcpy(iv_friendly_name, ipaddr.iv_friendly_name);
270
271     if (!ipaddr.addr_changed)
272     {
273       memcpy(output_buffer, ipaddr.output_buffer,
274              sizeof(unsigned char) * OUTBUFF);
275       addr_changed = false;
276     }
277   }
278 }
279
280 //-----[ construct an IP address with a GenAddress ]---------------------
281 IpAddress::IpAddress(const GenAddress &genaddr)
282   : iv_friendly_name_status(0)
283 {
284   ADDRESS_TRACE;
285
286   // always initialize what type this object is
287   smival.syntax = sNMP_SYNTAX_IPADDR;
288   smival.value.string.len = IPLEN;
289   smival.value.string.ptr = address_buffer;
290
291   memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
292   output_buffer[0]=0;
293
294   // allow use of an ip or udp genaddress
295   valid_flag = genaddr.valid();
296   if (valid_flag)
297   {
298     if (genaddr.get_type() == type_ip)
299     {
300       // copy in the IP address data
301       *this = genaddr.cast_ipaddress();
302       return;
303     }
304     else if (genaddr.get_type() == type_udp)
305     {
306       // copy in the IP address data
307       *this = genaddr.cast_udpaddress();
308       return;
309     }
310   }
311   valid_flag = false;
312   addr_changed = true;
313 }
314
315 //-----[ IP Address general = operator ]-------------------------------
316 SnmpSyntax& IpAddress::operator=(const SnmpSyntax &val)
317 {
318   ADDRESS_TRACE;
319
320   if (this == &val) return *this; // protect against assignment from itself
321
322   addr_changed = true;
323   valid_flag = false;        // will get set TRUE if really valid
324   memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
325
326   if (val.valid())
327   {
328     switch (val.get_syntax())
329     {
330       case sNMP_SYNTAX_IPADDR:
331       case sNMP_SYNTAX_OCTETS:
332         if ((((IpAddress &)val).smival.value.string.len == IPLEN) ||
333             (((IpAddress &)val).smival.value.string.len == UDPIPLEN))
334         {
335           MEMCPY(address_buffer,
336                  ((IpAddress &)val).smival.value.string.ptr, IPLEN);
337           valid_flag = true;
338           ip_version = version_ipv4;
339           smival.value.string.len = IPLEN;
340         }
341         else if ((((IpAddress &)val).smival.value.string.len == IP6LEN_NO_SCOPE) ||
342                  (((IpAddress &)val).smival.value.string.len == UDPIP6LEN_NO_SCOPE))
343         {
344           MEMCPY(address_buffer,
345                  ((IpAddress &)val).smival.value.string.ptr, IP6LEN_NO_SCOPE);
346           valid_flag = true;
347           ip_version = version_ipv6;
348           smival.value.string.len = IP6LEN_NO_SCOPE;
349           have_ipv6_scope = false;
350         }
351         else if ((((IpAddress &)val).smival.value.string.len == IP6LEN_WITH_SCOPE) ||
352                  (((IpAddress &)val).smival.value.string.len == UDPIP6LEN_WITH_SCOPE))
353         {
354           MEMCPY(address_buffer,
355                  ((IpAddress &)val).smival.value.string.ptr, IP6LEN_WITH_SCOPE);
356           valid_flag = true;
357           ip_version = version_ipv6;
358           smival.value.string.len = IP6LEN_WITH_SCOPE;
359           have_ipv6_scope = true;
360         }
361         break;
362
363         // NOTE: as a value add, other types could have "logical"
364         // mappings, i.e. integer32 and unsigned32
365     }
366   }
367   return *this;
368 }
369
370 //------[ assignment to another ipaddress object overloaded ]-----------------
371 IpAddress& IpAddress::operator=(const IpAddress &ipaddr)
372 {
373   ADDRESS_TRACE;
374
375   if (this == &ipaddr) return *this; // protect against assignment from itself
376
377   valid_flag = ipaddr.valid_flag;
378   memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
379
380   if (valid_flag)
381   {
382     if (ipaddr.ip_version == version_ipv4)
383     {
384       MEMCPY(address_buffer, ipaddr.address_buffer, IPLEN);
385       ip_version = version_ipv4;
386       smival.value.string.len = IPLEN;
387     }
388     else
389     {
390       if (ipaddr.have_ipv6_scope)
391       {
392         MEMCPY(address_buffer, ipaddr.address_buffer, IP6LEN_WITH_SCOPE);
393         ip_version = version_ipv6;
394         smival.value.string.len = IP6LEN_WITH_SCOPE;
395         have_ipv6_scope = true;
396       }
397       else
398       {
399         MEMCPY(address_buffer, ipaddr.address_buffer, IP6LEN_NO_SCOPE);
400         ip_version = version_ipv6;
401         smival.value.string.len = IP6LEN_NO_SCOPE;
402         have_ipv6_scope = false;
403       }
404     }
405     strcpy(iv_friendly_name, ipaddr.iv_friendly_name);
406
407     if (ipaddr.addr_changed)
408       addr_changed = true;
409     else
410     {
411       memcpy(output_buffer, ipaddr.output_buffer,
412              sizeof(unsigned char) * OUTBUFF);
413       addr_changed = false;
414     }
415   }
416   else
417     addr_changed = true;
418   return *this;
419 }
420
421 IpAddress& IpAddress::operator=(const char *inaddr)
422 {
423   ADDRESS_TRACE;
424
425   valid_flag = parse_address(inaddr);
426   addr_changed = true;
427   return *this;
428 }
429
430 //-------[ return the friendly name ]----------------------------------
431 char *IpAddress::friendly_name(int &status)
432 {
433   ADDRESS_TRACE;
434
435   if ((iv_friendly_name[0]==0) && (valid_flag))
436     this->addr_to_friendly();
437   status = iv_friendly_name_status;
438   return iv_friendly_name;
439 }
440
441 // parse a dotted string
442 int IpAddress::parse_dotted_ipstring(const char *inaddr)
443 {
444   ADDRESS_TRACE;
445
446   int token_count=0;
447   char temp[30];  // temp buffer for destruction
448
449   // check len, an ip can never be bigger than 15
450   // 123456789012345
451   // XXX.XXX.XXX.XXX
452   if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
453
454   strcpy(temp, inaddr);
455   trim_white_space(temp);
456   if (strlen(temp) > 15) return FALSE;
457
458   /* Check for the following:
459    * - exactly three dots
460    * - no dot at begin or end
461    * - at least a digit between two dots
462    * - only dots and digits allowed
463    */
464   char *ptr = temp;
465   int dot_count = 0;
466   bool last_char_was_dot = true;
467
468   while (*ptr)
469   {
470     if (*ptr == '.')
471     {
472       if (last_char_was_dot) return FALSE;
473       ++dot_count;
474       last_char_was_dot = true;
475     }
476     else if (my_isdigit(*ptr))
477     {
478       last_char_was_dot = false;
479     }
480     else
481       return FALSE;
482     ++ptr;
483   }
484   if ((dot_count != 3) || (last_char_was_dot))
485     return FALSE;
486
487   ptr = temp;
488   while (*ptr)
489   {
490     unsigned long number = 0;
491
492     if (*ptr == '.') ++ptr;    // skip over the dot
493
494     // grab a digit token and convert it to a long int
495     int digits = 0;
496     while ((*ptr) && (*ptr != '.'))
497     {
498       number = (number * 10) + *(ptr++) - '0';
499       ++digits;
500     }
501     if (digits > 3) return FALSE;
502     if (number > 255) return FALSE;
503
504     // stuff the value into the array and bump the counter
505     address_buffer[token_count++]= (unsigned char) number;
506   }
507
508   ip_version = version_ipv4;
509   smival.value.string.len = IPLEN;
510   return TRUE;
511 }
512
513 #define ATOI(x)    if      ((x >= 48) && (x <= 57)) x = x-48; /* 0-9 */ \
514                    else if ((x >= 97) && (x <=102)) x = x-87; /* a-f */ \
515                    else if ((x >= 65) && (x <= 70)) x = x-55; /* A-F */ \
516                    else x=0
517
518 // parse a coloned string
519 int IpAddress::parse_coloned_ipstring(const char *inaddr)
520 {
521   ADDRESS_TRACE;
522
523   unsigned char tmp_address_buffer[ADDRBUF];
524   char temp[60];  // temp buffer for destruction
525
526   // check len, an ipv6 can never be bigger than 39 + 11
527   // 123456789012345678901234567890123456789
528   // 1BCD:2BCD:3BCD:4BCD:5BCD:6BCD:7BCD:8BCD%4123456789
529   if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
530   strcpy(temp, inaddr);
531   trim_white_space(temp);
532
533   // first check for ipv6 scope
534   unsigned int scope = 0;
535   bool have_scope = false;
536
537   {
538       int scope_pos;
539       for (int i=strlen(temp)-1; i >=0 ; i--)
540       {
541           if (temp[i] == '%')
542           {
543               scope_pos = i;
544               have_scope = true;
545               break;
546           }
547           if (!isdigit(temp[i]))
548               break;
549       }
550       if (have_scope)
551       {
552           temp[scope_pos] = 0;
553           scope = atol(temp + scope_pos + 1);
554       }
555   }
556
557   if (strlen(temp) > 39) return FALSE;
558
559   char *in_ptr = temp;
560   char *out_ptr = (char*)tmp_address_buffer;
561   char *end_first_part = NULL;
562   char second[39];
563   int second_used = FALSE;
564   int colon_count = 0;
565   int had_double_colon = FALSE;
566   int last_was_colon = FALSE;
567   int had_dot = FALSE;
568   int dot_count = 0;
569   int digit_count = 0;
570   char digits[4];
571   char last_deliminiter = 0;
572
573   while (*in_ptr != 0)
574   {
575     if (*in_ptr == '.')
576     {
577       last_deliminiter = *in_ptr;
578       had_dot = TRUE;
579       dot_count++;
580       if (dot_count > 3)
581         return FALSE;
582       if ((digit_count > 3) || (digit_count < 1))
583         return FALSE;
584       for (int i=0; i<digit_count; i++)
585         if (!my_isdigit(digits[i]))
586           return FALSE;
587       digits[digit_count] = 0;
588       int value = atoi(digits);
589       if ((value > 0) && (value <= 255))
590         *out_ptr++ = (unsigned char) value;
591       else
592       {
593         if (strcmp(digits, "0") == 0)
594           *out_ptr++ = (unsigned char) 0;
595         else
596           return FALSE;
597       }
598       digit_count = 0;
599     }
600     else if (*in_ptr == ':')
601     {
602       last_deliminiter = *in_ptr;
603
604       if (had_dot)
605         return FALSE; // don't allow : after a dot
606
607       if (digit_count)
608       {
609         // move digits to right
610         {
611           for (int i=0; i<digit_count; i++)
612           {
613             ATOI(digits[digit_count - 1 - i]);
614             digits[3-i] = digits[digit_count - 1 - i];
615           }
616         }
617         {
618           for (int i=0; i<4-digit_count; i++)
619           digits[i] = 0;
620         }
621         {
622           // pack two digits into one byte
623           for (int i=0; i < 4; i += 2)
624           {
625             unsigned char c = digits[i];
626             unsigned char d = digits[i+1];
627             *out_ptr++ = (c*16 + d);
628           }
629         }
630         digit_count = 0;
631       }
632       colon_count++;
633       if (last_was_colon)
634       {
635         if (had_double_colon)
636           return FALSE;
637         end_first_part = out_ptr;
638         out_ptr = second;
639         second_used = TRUE;
640         had_double_colon = TRUE;
641       }
642       else
643       {
644         last_was_colon = TRUE;
645       }
646     }
647     else
648     {
649       if (digit_count >= 4)
650         return FALSE;
651       if (!isxdigit(*in_ptr))
652         return FALSE;
653       digits[digit_count] = tolower(*in_ptr);
654
655       digit_count++;
656       if (digit_count > 4)
657         return FALSE;
658       last_was_colon = 0;
659     }
660     in_ptr++;
661   }
662
663   // put last bytes from digits into buffer
664   if (digit_count)
665   {
666     if (last_deliminiter == ':')
667     {
668       {
669         // move digits to right
670         for (int i=0; i<digit_count; i++)
671         {
672           ATOI(digits[digit_count - 1 - i]);
673           digits[3-i] = digits[digit_count - 1 - i];
674         }
675       }
676       {
677         for (int i=0; i<4-digit_count; i++)
678           digits[i] = 0;
679       }
680       {
681         // pack two digits into one byte
682         for (int i=0; i < 4; i += 2)
683         {
684           unsigned char c = digits[i];
685           unsigned char d = digits[i+1];
686           *out_ptr++ = (c*16 + d);
687         }
688       }
689       digit_count = 0;
690     }
691     else if (last_deliminiter == '.')
692     {
693       if ((digit_count > 3) || (digit_count < 1))
694         return FALSE;
695       for (int i=0; i<digit_count; i++)
696         if (!my_isdigit(digits[i]))
697           return FALSE;
698       digits[digit_count] = 0;
699       int value = atoi(digits);
700       if ((value > 0) && (value <= 255))
701         *out_ptr++ = (unsigned char) value;
702       else
703       {
704         if (strcmp(digits, "0") == 0)
705           *out_ptr++ = (unsigned char) 0;
706         else
707           return FALSE;
708       }
709       //digit_count = 0;
710     }
711     else
712       return FALSE;
713   }
714
715   // must have between two and seven colons
716   if ((colon_count > 7) || (colon_count < 2))
717     return FALSE;
718
719   // if there was a dot there must be three of them
720   if ((dot_count > 0) && (dot_count != 3))
721     return FALSE;
722
723   if (second_used)
724   {
725     int len_first  = SAFE_INT_CAST(end_first_part - (char*)tmp_address_buffer);
726     int len_second = SAFE_INT_CAST(out_ptr - second);
727
728     int i;
729     for (i=0; i<IP6LEN_NO_SCOPE-(len_first + len_second); i++)
730       *end_first_part++ = 0;
731     for (i=0; i<len_second; i++)
732       *end_first_part++ = second[i];
733   }
734
735   if (!end_first_part)
736     end_first_part = out_ptr;
737
738   // check for short address
739   if (end_first_part - (char*)tmp_address_buffer != IP6LEN_NO_SCOPE)
740     return FALSE;
741
742   ip_version = version_ipv6;
743   if (have_scope)
744       smival.value.string.len = IP6LEN_WITH_SCOPE;
745   else
746       smival.value.string.len = IP6LEN_NO_SCOPE;
747
748   memcpy(address_buffer, tmp_address_buffer, ADDRBUF);
749
750   if (have_scope)
751   {
752     unsigned int *scope_p = (unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
753     *scope_p = htonl(scope);
754     have_ipv6_scope = true;
755   }
756   else
757       have_ipv6_scope = false;
758
759   return TRUE;
760 }
761
762 #undef ATOI
763
764 //-----[ IP Address parse Address ]---------------------------------
765 bool IpAddress::parse_address(const char *inaddr)
766 {
767   ADDRESS_TRACE;
768
769 #if !defined HAVE_GETHOSTBYNAME_R && !defined HAVE_REENTRANT_GETHOSTBYNAME
770 #ifdef _THREADS
771   SnmpSynchronize s(syscall_mutex);
772 #endif
773 #endif
774
775   addr_changed = true;
776
777   // parse the input char array fill up internal buffer with four ip
778   // bytes set and return validity flag
779
780   char ds[61];
781
782   // intialize the friendly_name member variable
783   memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
784   iv_friendly_name_status = 0;
785
786   // is this a dotted IP notation string or a friendly name
787   if (parse_dotted_ipstring(inaddr))
788   {
789     // since this is a valid dotted string don't do any DNS
790     return TRUE;
791   }
792   else if (parse_coloned_ipstring(inaddr))
793   {
794     // since this is a valid ipv6 string don't do any DNS
795     return TRUE;
796   }
797   else // not a dotted string, try to resolve it via DNS
798   {
799 #if defined (CPU) && CPU == PPC603
800   int lookupResult = hostGetByName(inaddr);
801
802   if (lookupResult == ERROR)
803   {
804       iv_friendly_name_status = lookupResult;
805       return FALSE;
806   }
807         // now lets check out the dotted string
808   strcpy(ds,inet_ntoa(lookupResult));
809
810   if (!parse_dotted_ipstring(ds))
811      return FALSE;
812
813         // save the friendly name
814   strcpy(iv_friendly_name, inaddr);
815
816   return TRUE;
817
818 #else
819   hostent *lookupResult = 0;
820
821 #ifdef HAVE_GETHOSTBYNAME_R
822     char buf[2048]; // TODO: Too big buffer?
823     int herrno = 0;
824     hostent lookup_buf;
825 #if defined(__sun) || defined (__QNX_NEUTRINO)
826     lookupResult = gethostbyname_r(inaddr, &lookup_buf, buf, 2048, &herrno);
827 #else    
828     gethostbyname_r(inaddr, &lookup_buf, buf, 2048, &lookupResult, &herrno);
829 #endif
830 #ifdef SNMP_PP_IPv6
831     if (!lookupResult)
832     {
833 #ifdef __sun
834       lookupResult = gethostbyname_r(inaddr, AF_INET6, &lookup_buf, buf, 2048,
835                                      &lookupResult, &herrno);
836 #else        
837       gethostbyname2_r(inaddr, AF_INET6, &lookup_buf, buf, 2048,
838                         &lookupResult, &herrno);
839 #endif
840     }
841 #endif // SNMP_PP_IPv6
842 #else // not HAVE_GETHOSTBYNAME_R
843     lookupResult = gethostbyname(inaddr);
844 #ifdef SNMP_PP_IPv6
845     if (!lookupResult)
846     {
847 #ifdef HAVE_GETHOSTBYNAME2
848       lookupResult = gethostbyname2(inaddr, AF_INET6);
849 #else
850       lookupResult = gethostbyname(inaddr);
851 #endif // HAVE_GETHOSTBYNAME2
852     }
853 #endif // SNMP_PP_IPv6
854 #endif // HAVE_GETHOSTBYNAME_R
855     if (lookupResult)
856     {
857 #ifdef SNMP_PP_IPv6
858       if (lookupResult->h_length == sizeof(in6_addr))
859       {
860         in6_addr ipAddr;
861         memcpy((void *) &ipAddr, (void *) lookupResult->h_addr,
862                sizeof(in6_addr));
863
864         // now lets check out the coloned string
865         if (!inet_ntop(AF_INET6, &ipAddr, ds, 60))
866           return FALSE;
867         debugprintf(4, "from inet_ntop: %s", ds);
868         if (!parse_coloned_ipstring(ds))
869           return FALSE;
870
871         // save the friendly name
872         strcpy(iv_friendly_name, inaddr);
873         
874         return TRUE;
875       }
876 #endif // SNMP_PP_IPv6
877       if (lookupResult->h_length == sizeof(in_addr))
878       {
879         in_addr ipAddr;
880
881         memcpy((void *) &ipAddr, (void *) lookupResult->h_addr,
882                sizeof(in_addr));
883
884         // now lets check out the dotted string
885         strcpy(ds,inet_ntoa(ipAddr));
886
887         if (!parse_dotted_ipstring(ds))
888           return FALSE;
889
890         // save the friendly name
891         strcpy(iv_friendly_name, inaddr);
892
893         return TRUE;
894       }
895     }         // end if lookup result
896     else
897     {
898 #ifdef HAVE_GETHOSTBYNAME_R
899       iv_friendly_name_status = herrno;
900 #else
901       iv_friendly_name_status = h_errno;
902 #endif
903       return FALSE;
904     }
905 #endif //PPC603
906   }  // end else not a dotted string
907   return TRUE;
908 }
909
910 // using the currently defined address, do a DNS
911 // and try to fill up the name
912 int IpAddress::addr_to_friendly()
913 {
914   ADDRESS_TRACE;
915
916 #if !defined HAVE_GETHOSTBYADDR_R && !defined HAVE_REENTRANT_GETHOSTBYADDR
917 #ifdef _THREADS
918   SnmpSynchronize s(syscall_mutex);
919 #endif
920 #endif
921
922 #if defined (CPU) && CPU == PPC603
923   int lookupResult;
924   char hName[MAXHOSTNAMELEN+1];
925 #else
926   hostent *lookupResult;
927 #endif
928   char    ds[61];
929
930   // can't look up an invalid address
931   if (!valid_flag) return -1;
932
933   // lets try and get the friendly name from the DNS
934   strcpy(ds, this->IpAddress::get_printable());
935
936 #if !(defined (CPU) && CPU == PPC603) && defined HAVE_GETHOSTBYADDR_R
937   int herrno = 0;
938   hostent lookup;
939   char buf[2048]; // TODO: Buf size too big?
940 #endif
941   if (ip_version == version_ipv4)
942   {
943     in_addr ipAddr;
944
945 #if defined HAVE_INET_ATON
946     if (inet_aton((char*)ds, &ipAddr) == 0)
947       return -1;    // bad address
948 #elif defined HAVE_INET_PTON
949     if (inet_pton(AF_INET, (char*)ds, &ipAddr) <= 0)
950       return -1; // bad address
951 #else
952     ipAddr.s_addr = inet_addr((char*)ds);
953     if (ipAddr.s_addr == INADDR_NONE)
954       return -1; // bad address
955 #endif
956
957 #if defined (CPU) && CPU == PPC603
958         lookupResult = hostGetByAddr(ipAddr.s_addr, hName);
959 #elif defined HAVE_GETHOSTBYADDR_R
960 #if defined(__sun) || defined(__QNX_NEUTRINO)
961     lookupResult = gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
962                                    AF_INET, &lookup, buf, 2048, &herrno);
963 #else
964     gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
965                     AF_INET, &lookup, buf, 2048, &lookupResult, &herrno);
966 #endif
967 #else
968     lookupResult = gethostbyaddr((char *) &ipAddr, sizeof(in_addr),
969                                  AF_INET);
970 #endif
971   }
972   else
973   {
974 #ifdef SNMP_PP_IPv6
975     if (have_ipv6_scope)
976     {
977         // remove scope from ds
978         for (int i=strlen(ds); i >=0; i--)
979             if (ds[i] == '%')
980             {
981                 ds[i] = 0;
982                 break;
983             }
984     }
985
986     in6_addr ipAddr;
987
988     if (inet_pton(AF_INET6, (char*)ds, &ipAddr) <= 0)
989       return -1; // bad address
990
991 #if defined (CPU) && CPU == PPC603
992         lookupResult = hostGetByAddr(ipAddr.s_addr, hName);
993 #elif defined HAVE_GETHOSTBYADDR_R
994 #if defined(__sun) || defined(__QNX_NEUTRINO)
995     lookupResult = gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
996                                    AF_INET6, &lookup, buf, 2048, &herrno);
997 #else
998     gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
999                     AF_INET6, &lookup, buf, 2048, &lookupResult, &herrno);
1000 #endif
1001 #else
1002     lookupResult = gethostbyaddr((char *) &ipAddr, sizeof(in6_addr),
1003                                  AF_INET6);
1004 #endif // HAVE_GETHOSTBYADDR_R
1005 #else
1006     return -1;
1007 #endif // SNMP_PP_IPv6
1008   }
1009   // if we found the name, then update the iv friendly name
1010 #if defined (CPU) && CPU == PPC603
1011   if (lookupResult != ERROR)
1012   {
1013     strncpy(iv_friendly_name, hName, MAX_FRIENDLY_NAME);
1014     return 0;
1015   }
1016   else
1017   {
1018     iv_friendly_name_status = lookupResult;
1019         return lookupResult;
1020   }
1021
1022   return -1; //should not get here
1023
1024 #else
1025   if (lookupResult)
1026   {
1027     strcpy(iv_friendly_name, lookupResult->h_name);
1028     return 0;
1029   }
1030   else
1031   {
1032 #ifdef HAVE_GETHOSTBYADDR_R
1033     iv_friendly_name_status = herrno;
1034 #else
1035     iv_friendly_name_status = h_errno;
1036 #endif
1037     return iv_friendly_name_status;
1038   }
1039 #endif //PPC603
1040 }
1041
1042 unsigned int IpAddress::get_scope() const
1043 {
1044   ADDRESS_TRACE;
1045
1046   if (valid_flag)
1047   {
1048     const unsigned int *scope;
1049     if ((ip_version == version_ipv6) && (have_ipv6_scope))
1050       scope = (const unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
1051     else
1052       return (unsigned int)-1;
1053
1054     return ntohl(*scope);
1055   }
1056   return (unsigned int)-1; // don't use uninitialized memory
1057 }
1058
1059 bool IpAddress::set_scope(const unsigned int scope)
1060 {
1061   ADDRESS_TRACE;
1062
1063   if (!valid_flag || (ip_version != version_ipv6))
1064       return false;
1065
1066   unsigned int *scope_ptr = (unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
1067
1068   *scope_ptr = htonl(scope);
1069   addr_changed = true;
1070   smival.value.string.len = IP6LEN_WITH_SCOPE;
1071   have_ipv6_scope = true;
1072   return true;
1073 }
1074
1075 //----[ IP address format output ]------------------------------------
1076 void IpAddress::format_output() const
1077 {
1078   ADDRESS_TRACE;
1079
1080   // if valid format else null it
1081   if (valid_flag)
1082   {
1083     if (ip_version == version_ipv4)
1084       sprintf((char *) output_buffer,"%d.%d.%d.%d",address_buffer[0],
1085                address_buffer[1], address_buffer[2], address_buffer[3]);
1086     else
1087       if (have_ipv6_scope)
1088         sprintf((char *) output_buffer,
1089                 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1090                 "%02x%02x:%02x%02x:%02x%02x:%02x%02x%%%d",
1091                 address_buffer[ 0], address_buffer[ 1], address_buffer[ 2],
1092                 address_buffer[ 3], address_buffer[ 4], address_buffer[ 5],
1093                 address_buffer[ 6], address_buffer[ 7], address_buffer[ 8],
1094                 address_buffer[ 9], address_buffer[10], address_buffer[11],
1095                 address_buffer[12], address_buffer[13], address_buffer[14],
1096                 address_buffer[15], get_scope());
1097       else
1098         sprintf((char *) output_buffer,
1099                 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1100                 "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
1101                 address_buffer[ 0], address_buffer[ 1], address_buffer[ 2],
1102                 address_buffer[ 3], address_buffer[ 4], address_buffer[ 5],
1103                 address_buffer[ 6], address_buffer[ 7], address_buffer[ 8],
1104                 address_buffer[ 9], address_buffer[10], address_buffer[11],
1105                 address_buffer[12], address_buffer[13], address_buffer[14],
1106                 address_buffer[15]);
1107   }
1108   else
1109     *(char *)output_buffer = 0;
1110   IpAddress *nc_this = PP_CONST_CAST(IpAddress*, this);
1111   nc_this->addr_changed = false;
1112 }
1113
1114 //-----------------------------------------------------------------
1115 // logically and two IPaddresses and
1116 // return the new one
1117 void IpAddress::mask(const IpAddress& ipaddr)
1118 {
1119   ADDRESS_TRACE;
1120
1121   if (valid() && ipaddr.valid())
1122   {
1123     int count = (ip_version == version_ipv4) ? IPLEN : IP6LEN_NO_SCOPE;
1124
1125     for (int i = 0; i < count; i++)
1126       address_buffer[i] = address_buffer[i] & ipaddr.address_buffer[i];
1127     addr_changed = true;
1128   }
1129 }
1130
1131
1132 // Get the count of matching bits from the left.
1133 int IpAddress::get_match_bits(const IpAddress match_ip) const
1134 {
1135   ADDRESS_TRACE;
1136
1137   int bits = 0;
1138
1139   if (valid() && match_ip.valid() &&
1140       (ip_version == match_ip.ip_version))
1141   {
1142     int count = (ip_version == version_ipv4) ? IPLEN : IP6LEN_NO_SCOPE;
1143
1144     for (int i = 0; i < count; i++)
1145     {
1146         if (address_buffer[i] == match_ip.address_buffer[i])
1147             bits += 8;
1148         else
1149         {
1150             bits += 7;
1151             unsigned char c1 = address_buffer[i] >> 1;
1152             unsigned char c2 = match_ip.address_buffer[i] >> 1;
1153             while (c1 != c2)
1154             {
1155                 c1 = c1 >> 1;
1156                 c2 = c2 >> 1;
1157                 bits--;
1158             }
1159             break;
1160         }
1161     }
1162   }
1163
1164   return bits;
1165 }
1166
1167 // Map a IPv4 Address to a IPv6 address.
1168 int IpAddress::map_to_ipv6()
1169 {
1170   ADDRESS_TRACE;
1171
1172   if (!valid())
1173     return FALSE;
1174
1175   if (ip_version != version_ipv4)
1176     return FALSE;
1177
1178   /* just copy IPv4 address to the end of  the buffer
1179      zero the first 10 bytes and fill 2 Bytes with 0xff */
1180   memcpy(&address_buffer[12], address_buffer, 4);
1181   memset(address_buffer, 0, 10);
1182   address_buffer[10] = 0xff;
1183   address_buffer[11] = 0xff;
1184
1185   smival.value.string.len = IP6LEN_NO_SCOPE;
1186   ip_version = version_ipv6;
1187   have_ipv6_scope = false;
1188
1189   addr_changed = true;
1190   return TRUE;
1191 }
1192
1193 // Reset the object
1194 void IpAddress::clear()
1195 {
1196   Address::clear();
1197   memset(output_buffer, 0, sizeof(output_buffer));
1198   iv_friendly_name_status = 0;
1199   ip_version = version_ipv4;
1200   have_ipv6_scope = false;
1201   memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
1202   smival.value.string.len = IPLEN;
1203 }
1204
1205 //=======================================================================
1206 //========== Udp Address Implementation =================================
1207 //=======================================================================
1208
1209 //-------[ construct an IP address with no agrs ]----------------------
1210 UdpAddress::UdpAddress()
1211   : IpAddress()
1212 {
1213   ADDRESS_TRACE;
1214
1215   // Inherits IP Address attributes
1216   // Always initialize (override) what type this object is
1217   smival.syntax = sNMP_SYNTAX_OCTETS;
1218   smival.value.string.len = UDPIPLEN;
1219   smival.value.string.ptr = address_buffer;
1220
1221   sep = ':';
1222   set_port(0);
1223 }
1224
1225 //-----------------[ construct an Udp address with another Udp address ]---
1226 UdpAddress::UdpAddress(const UdpAddress &udpaddr)
1227   : IpAddress(udpaddr)
1228 {
1229   ADDRESS_TRACE;
1230
1231   // always initialize SMI info
1232   smival.syntax = sNMP_SYNTAX_OCTETS;
1233   smival.value.string.len = udpaddr.smival.value.string.len;
1234   smival.value.string.ptr = address_buffer;
1235
1236   // Copy the port value
1237   sep = ':';
1238   set_port(udpaddr.get_port());
1239
1240   if (!udpaddr.addr_changed)
1241   {
1242     memcpy(output_buffer, udpaddr.output_buffer,
1243            sizeof(unsigned char) * OUTBUFF);
1244     addr_changed = false;
1245   }
1246 }
1247
1248 // constructor with a dotted string
1249 UdpAddress::UdpAddress(const char *inaddr) : IpAddress()
1250 {
1251   ADDRESS_TRACE;
1252
1253   // always initialize SMI info
1254   smival.syntax = sNMP_SYNTAX_OCTETS;
1255   smival.value.string.len = UDPIPLEN;
1256   smival.value.string.ptr = address_buffer;
1257
1258   valid_flag = parse_address(inaddr);
1259   addr_changed = true;
1260 }
1261
1262 //-----------------[ construct a UdpAddress from a GenAddress ]--------------
1263 UdpAddress::UdpAddress(const GenAddress &genaddr) : IpAddress()
1264 {
1265   ADDRESS_TRACE;
1266
1267   // always initialize SMI info
1268   smival.syntax = sNMP_SYNTAX_OCTETS;
1269   smival.value.string.len = UDPIPLEN;
1270   smival.value.string.ptr = address_buffer;
1271
1272   valid_flag = genaddr.valid();
1273
1274   // allow use of an ip or udp genaddress
1275   if (valid_flag)
1276   {
1277     if (genaddr.get_type() == type_udp)
1278     {
1279       *this = genaddr.cast_udpaddress();      // copy in the IP address data
1280     }
1281     else if (genaddr.get_type() == type_ip)
1282     {
1283       *this = genaddr.cast_ipaddress();      // copy in the IP address data
1284     }
1285     else
1286     {
1287       valid_flag = false;
1288     }
1289   }
1290   sep = ':';
1291 }
1292
1293 //--------[ construct a udp from an IpAddress ]--------------------------
1294 UdpAddress::UdpAddress(const IpAddress &ipaddr)
1295     : IpAddress(ipaddr)
1296 {
1297   ADDRESS_TRACE;
1298
1299    // always initialize SMI info
1300   smival.syntax = sNMP_SYNTAX_OCTETS;
1301   if (ip_version == version_ipv4)
1302       smival.value.string.len = UDPIPLEN;
1303   else
1304       if (have_ipv6_scope)
1305           smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
1306       else
1307           smival.value.string.len = UDPIP6LEN_NO_SCOPE;
1308   smival.value.string.ptr = address_buffer;
1309
1310   sep = ':';
1311   addr_changed = true;
1312   set_port(0);
1313 }
1314
1315 // copy an instance of this Value
1316 SnmpSyntax& UdpAddress::operator=(const SnmpSyntax &val)
1317 {
1318   ADDRESS_TRACE;
1319
1320   if (this == &val) return *this;   // protect against assignment from itself
1321
1322   valid_flag = false;                // will get set TRUE if really valid
1323   addr_changed = true;
1324   if (val.valid())
1325   {
1326     switch (val.get_syntax())
1327     {
1328       case sNMP_SYNTAX_IPADDR:
1329       {
1330         UdpAddress temp_udp(val.get_printable());
1331         *this = temp_udp;        // valid_flag is set by the udp assignment
1332         break;
1333       }
1334       case sNMP_SYNTAX_OCTETS:
1335         if (((UdpAddress &)val).smival.value.string.len == UDPIPLEN)
1336         {
1337           MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
1338                  UDPIPLEN);
1339           memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
1340           valid_flag = true;
1341           ip_version = version_ipv4;
1342           smival.value.string.len = UDPIPLEN;
1343         }
1344         else if (((UdpAddress &)val).smival.value.string.len == UDPIP6LEN_NO_SCOPE)
1345         {
1346           MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
1347                  UDPIP6LEN_NO_SCOPE);
1348           memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
1349           valid_flag = true;
1350           ip_version = version_ipv6;
1351           smival.value.string.len = UDPIP6LEN_NO_SCOPE;
1352           have_ipv6_scope = false;
1353         }
1354         else if (((UdpAddress &)val).smival.value.string.len == UDPIP6LEN_WITH_SCOPE)
1355         {
1356           MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
1357                  UDPIP6LEN_WITH_SCOPE);
1358           memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
1359           valid_flag = true;
1360           ip_version = version_ipv6;
1361           smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
1362           have_ipv6_scope = true;
1363         }
1364         break;
1365         // NOTE: as a value add, other types could have "logical"
1366         // mappings, i.e. integer32 and unsigned32
1367     }
1368   }
1369   return *this;
1370 }
1371
1372 // assignment to another UdpAddress object overloaded
1373 UdpAddress& UdpAddress::operator=(const UdpAddress &udpaddr)
1374 {
1375   ADDRESS_TRACE;
1376
1377   if (this == &udpaddr) return *this; // protect against assignment from itself
1378
1379   (IpAddress &)*this = udpaddr; // use ancestor assignment for ipaddr value
1380   if (ip_version == version_ipv4)
1381     smival.value.string.len = UDPIPLEN;
1382   else
1383       if (have_ipv6_scope)
1384           smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
1385       else
1386           smival.value.string.len = UDPIP6LEN_NO_SCOPE;
1387
1388   set_port(udpaddr.get_port());        // copy to port value
1389   if (udpaddr.addr_changed)
1390   {
1391     addr_changed = true;
1392   }
1393   else
1394   {
1395     memcpy(output_buffer, udpaddr.output_buffer,
1396            sizeof(unsigned char) * OUTBUFF);
1397     addr_changed = false;
1398   }
1399
1400   return *this;
1401 }
1402
1403 // assignment to another UdpAddress object overloaded
1404 UdpAddress& UdpAddress::operator=(const IpAddress &ipaddr)
1405 {
1406   ADDRESS_TRACE;
1407
1408   if (this == &ipaddr) return *this; // protect against assignment from itself
1409
1410   (IpAddress &)*this = ipaddr; // use ancestor assignment for ipaddr value
1411
1412   if (ip_version == version_ipv4)
1413     smival.value.string.len = UDPIPLEN;
1414   else
1415       if (have_ipv6_scope)
1416           smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
1417       else
1418           smival.value.string.len = UDPIP6LEN_NO_SCOPE;
1419
1420   set_port(0);        // copy to port value
1421   addr_changed = true;
1422   return *this;
1423 }
1424
1425 UdpAddress& UdpAddress::operator=(const char *inaddr)
1426 {
1427   ADDRESS_TRACE;
1428
1429   valid_flag = parse_address(inaddr);
1430   addr_changed = true;
1431   return *this;
1432 }
1433
1434 //-----[ IP Address parse Address ]---------------------------------
1435 bool UdpAddress::parse_address(const char *inaddr)
1436 {
1437   ADDRESS_TRACE;
1438
1439   addr_changed = true;
1440
1441   char buffer[MAX_FRIENDLY_NAME];
1442
1443   if (inaddr && (strlen(inaddr)< MAX_FRIENDLY_NAME))
1444   {
1445     strcpy(buffer, inaddr);
1446     trim_white_space(buffer);
1447   }
1448   else
1449   {
1450     valid_flag = false;
1451     return FALSE;
1452   }
1453   // look for port info @ the end of the string
1454   // port can be delineated by a ':' or a '/'
1455   // if neither are present then just treat it
1456   // like a normal IpAddress
1457
1458   int remove_brackets = FALSE;
1459   int found = FALSE;
1460   int pos = (int)strlen(buffer) - 1; // safe to cast as max is MAX_FRIENDLY_NAME
1461   int do_loop = TRUE;
1462   int another_colon_found = FALSE;
1463   bool scope_found = false;
1464
1465   if (pos < 0)
1466   {
1467     valid_flag = false;
1468     return FALSE;
1469   }
1470
1471   // search from the end, to find the start of the port 
1472   // [ipv4]:port [ipv4]/port ipv4/port ipv4:port [ipv4] ipv4
1473   // [ipv6]:port [ipv6]/port ipv6/port           [ipv6] ipv6
1474   while (do_loop)
1475   {
1476     if (buffer[pos] == '/')
1477     {
1478       found = TRUE;
1479       sep='/';
1480       if (buffer[pos -1] == ']')
1481         remove_brackets = TRUE;
1482       break;
1483     }
1484     if (buffer[pos] == ':')
1485     {
1486       if ((pos > 1) && (buffer[pos -1] == ']'))
1487       {
1488         found = TRUE;
1489         remove_brackets = TRUE;
1490         sep=':';
1491         break;
1492       }
1493
1494       for (int i=pos - 1; i >= 0 ; i--)
1495       {
1496           if (buffer[i] == ':')
1497               another_colon_found = TRUE;
1498           if (buffer[i] == '%')
1499               scope_found = true;
1500       }
1501       if (scope_found) // must be ipv6, so reset colon_found
1502           another_colon_found = false;
1503
1504       if (!another_colon_found)
1505       {
1506         sep=':';
1507         found = TRUE;
1508         break;
1509       }
1510     }
1511     if (buffer[pos] == ']')
1512     {
1513       // we found a ] without following a port, so increase pos
1514       ++pos;
1515       remove_brackets = TRUE;
1516       break;
1517     }
1518     pos--;
1519     do_loop = ((found == FALSE) && (pos >= 0) &&
1520                (another_colon_found == FALSE));
1521   }
1522
1523   if (remove_brackets)
1524   {
1525     buffer[pos-1] = 0;
1526     buffer[0] = ' ';
1527   }
1528
1529   bool result;
1530   unsigned short port;
1531
1532   if (found)
1533   {
1534     buffer[pos] = 0;
1535     port = atoi(&buffer[pos+1]);
1536     result = IpAddress::parse_address(buffer);
1537   }
1538   else
1539   {
1540     port = 0;
1541     result = IpAddress::parse_address(buffer);
1542   }
1543
1544   if (ip_version == version_ipv4)
1545     smival.value.string.len = UDPIPLEN;
1546   else
1547       if (have_ipv6_scope)
1548           smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
1549       else
1550           smival.value.string.len = UDPIP6LEN_NO_SCOPE;
1551
1552   set_port(port);
1553   return result;
1554 }
1555
1556
1557 //--------[ set the port number ]---------------------------------------
1558 void UdpAddress::set_port(const unsigned short p)
1559 {
1560   ADDRESS_TRACE;
1561
1562   unsigned short *port_nbo;
1563   if (ip_version == version_ipv4)
1564     port_nbo = (unsigned short*)(address_buffer + IPLEN);
1565   else
1566       if (have_ipv6_scope)
1567           port_nbo = (unsigned short*)(address_buffer + IP6LEN_WITH_SCOPE);
1568       else
1569           port_nbo = (unsigned short*)(address_buffer + IP6LEN_NO_SCOPE);
1570   *port_nbo = htons(p);
1571   addr_changed = true;
1572 }
1573
1574 //---------[ get the port number ]--------------------------------------
1575 unsigned short UdpAddress::get_port() const
1576 {
1577   ADDRESS_TRACE;
1578
1579   if (valid_flag)
1580   {
1581     const unsigned short *port_nbo;
1582     if (ip_version == version_ipv4)
1583       port_nbo = (const unsigned short*)(address_buffer + IPLEN);
1584     else
1585         if (have_ipv6_scope)
1586             port_nbo = (const unsigned short*)(address_buffer + IP6LEN_WITH_SCOPE);
1587         else
1588             port_nbo = (const unsigned short*)(address_buffer + IP6LEN_NO_SCOPE);
1589
1590     return ntohs(*port_nbo);
1591   }
1592   return 0;// don't use uninitialized memory
1593 }
1594
1595 //----[ UDP address format output ]------------------------------------
1596 void UdpAddress::format_output() const
1597 {
1598   ADDRESS_TRACE;
1599
1600   IpAddress::format_output(); // allow ancestors to format their buffers
1601
1602   // if valid format else null it
1603   if (valid_flag)
1604   {
1605     if (ip_version == version_ipv4)
1606       sprintf((char *) output_buffer,"%s%c%d",
1607                IpAddress::get_printable(),
1608                '/',//TODO:look for problems in old code and change to "sep"
1609                get_port() );
1610       else
1611         sprintf((char *) output_buffer,"[%s]%c%d",
1612                  IpAddress::get_printable(),
1613                  '/',//TODO:look for problems in old code and change to "sep"
1614                  get_port() );
1615   }
1616   else
1617     *(char*)output_buffer = 0;
1618   UdpAddress *nc_this = PP_CONST_CAST(UdpAddress*, this);
1619   nc_this->addr_changed = false;
1620 }
1621
1622 bool UdpAddress::set_scope(const unsigned int scope)
1623 {
1624   ADDRESS_TRACE;
1625
1626   /* Save the port, as IpAddress::set_scope destroys it */
1627   unsigned short old_port = get_port();
1628  
1629   if (!IpAddress::set_scope(scope))
1630       return false;
1631
1632   smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
1633
1634   set_port(old_port);
1635
1636   return true;
1637 }
1638
1639 /**
1640  * Map a IPv4 UDP address to a IPv6 UDP address.
1641  *
1642  * @return - TRUE if no error occured.
1643  */
1644 int UdpAddress::map_to_ipv6()
1645 {
1646   ADDRESS_TRACE;
1647
1648   /* Save the port, as IpAddress::map_to_ipv6 destroys it */
1649   unsigned short old_port = get_port();
1650
1651   /* Map IpAddress */
1652   if (!IpAddress::map_to_ipv6())
1653     return FALSE;
1654
1655   set_port(old_port);
1656   smival.value.string.len = UDPIP6LEN_NO_SCOPE;
1657   ip_version = version_ipv6;
1658
1659   addr_changed = true;
1660   return TRUE;
1661 }
1662
1663
1664 #ifdef _IPX_ADDRESS
1665 //=======================================================================
1666 //=========== IPX Address Implementation ================================
1667 //=======================================================================
1668
1669 //----------[ constructor no args ]--------------------------------------
1670 IpxAddress::IpxAddress() : Address()
1671 {
1672   // always initialize SMI info
1673   smival.syntax = sNMP_SYNTAX_OCTETS;
1674   smival.value.string.len = IPXLEN;
1675   smival.value.string.ptr = address_buffer;
1676
1677   separator = 0;
1678   valid_flag = false;
1679   addr_changed = true;
1680 }
1681
1682
1683 //----------[ constructor with a string arg ]---------------------------
1684 IpxAddress::IpxAddress(const char  *inaddr):Address()
1685 {
1686   // always initialize SMI info
1687   smival.syntax = sNMP_SYNTAX_OCTETS;
1688   smival.value.string.len = IPXLEN;
1689   smival.value.string.ptr = address_buffer;
1690
1691   separator = 0;
1692   valid_flag = parse_address(inaddr);
1693   addr_changed = true;
1694 }
1695
1696
1697 //-----[ IPX Address copy constructor ]----------------------------------
1698 IpxAddress::IpxAddress(const IpxAddress &ipxaddr)
1699 {
1700   // always initialize SMI info
1701   smival.syntax = sNMP_SYNTAX_OCTETS;
1702   smival.value.string.len = IPXLEN;
1703   smival.value.string.ptr = address_buffer;
1704
1705   separator = 0;
1706   valid_flag = ipxaddr.valid_flag;
1707   if (valid_flag)
1708      MEMCPY(address_buffer, ipxaddr.address_buffer, IPXLEN);
1709   addr_changed = true;
1710 }
1711
1712
1713 //----[ construct an IpxAddress from a GenAddress ]---------------------------
1714 IpxAddress::IpxAddress(const GenAddress &genaddr)
1715 {
1716   // always initialize SMI info
1717   smival.syntax = sNMP_SYNTAX_OCTETS;
1718   smival.value.string.len = IPXLEN;
1719   smival.value.string.ptr = address_buffer;
1720
1721   valid_flag = genaddr.valid();
1722   // allow use of an ipx or ipxsock address
1723   if (valid_flag)
1724   {
1725     if ((genaddr.get_type() == type_ipx) )
1726     {
1727       *this = genaddr.cast_ipxaddress();     // copy in the Ipx address data
1728     }
1729     else if ((genaddr.get_type() == type_ipxsock) )
1730     {
1731       *this = genaddr.cast_ipxsockaddress();  // copy in the Ipx address data
1732     }
1733     else
1734       valid_flag = false;
1735   }
1736 }
1737
1738 //-----[ IPX Address general = operator ]-------------------------------
1739 SnmpSyntax& IpxAddress::operator=(const SnmpSyntax &val)
1740 {
1741   // protect against assignment from itself
1742   if (this == &val) return *this;
1743
1744   valid_flag = false;              // will set to TRUE if really valid
1745   if (val.valid()){
1746     switch (val.get_syntax()){
1747     case sNMP_SYNTAX_OCTETS:
1748       if (((IpxAddress &)val).smival.value.string.len == IPXLEN){
1749         MEMCPY(address_buffer, ((IpxAddress &)val).smival.value.string.ptr, IPXLEN);
1750         valid_flag = true;
1751       }
1752     break;
1753     }
1754   }
1755   addr_changed = true;
1756   return *this;
1757 }
1758
1759 //--------[ assignment to another IpAddress object overloaded ]----------
1760 IpxAddress& IpxAddress::operator=(const IpxAddress &ipxaddress)
1761 {
1762   if (this == &ipxaddress) return *this;// protect against assignment from self
1763
1764   valid_flag = ipxaddress.valid_flag;
1765   if (valid_flag)
1766     MEMCPY(address_buffer, ipxaddress.address_buffer, IPXLEN);
1767   addr_changed = true;
1768   return *this;
1769 }
1770
1771
1772 //-----[ IPX Address parse Address ]-----------------------------------
1773 // Convert a string to a ten byte ipx address
1774 // On success sets validity  TRUE or FALSE
1775 //
1776 //     IPX address format
1777 //
1778 //  NETWORK ID| MAC ADDRESS
1779 // 01 02 03 04|05 06 07 08 09 10
1780 // XX XX XX XX|XX XX XX XX XX XX
1781 //
1782 //   Valid input format
1783 //
1784 //   XXXXXXXX.XXXXXXXXXXXX
1785 //   Total length must be 21
1786 //   Must have a separator in it
1787 //   First string length must be 8
1788 //   Second string length must be 12
1789 //   Each char must take on value 0-F
1790 //
1791 //
1792 // Input formats recognized
1793 //
1794 //  XXXXXXXX.XXXXXXXXXXXX
1795 //  XXXXXXXX:XXXXXXXXXXXX
1796 //  XXXXXXXX-XXXXXXXXXXXX
1797 //  XXXXXXXX.XXXXXX-XXXXXX
1798 //  XXXXXXXX:XXXXXX-XXXXXX
1799 //  XXXXXXXX-XXXXXX-XXXXXX
1800 bool IpxAddress::parse_address(const char *inaddr)
1801 {
1802   char unsigned *str1,*str2;
1803   char temp[30];    // don't destroy original
1804   char unsigned *tmp;
1805   size_t z, tmplen;
1806
1807   // save the orginal source
1808   if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
1809   strcpy(temp, inaddr);
1810   trim_white_space(temp);
1811   tmplen = strlen(temp);
1812
1813   // bad total length check
1814   // 123456789012345678901
1815   // XXXXXXXX-XXXXXXXXXXXX  21 len
1816   //
1817   // XXXXXXXX-XXXXXX-XXXXXX 22 len
1818   // need at least 21 chars and no more than 22
1819   if ((tmplen <21) || (tmplen >22))
1820     return FALSE;
1821
1822   // convert the string to all lower case
1823   // this allows hex values to be in upper or lower
1824   for (z=0;z< tmplen;z++)
1825     temp[z] = tolower(temp[z]);
1826
1827   // check for separated nodeid
1828   // if found remove it
1829   if (temp[15] == '-')
1830   {
1831      for(z=16;z<tmplen;z++)
1832         temp[z-1] = temp[z];
1833      temp[tmplen-1] = 0;
1834   }
1835
1836   // no dot or colon separator check
1837   separator = temp[8];
1838   if ((separator != ':') &&
1839       (separator != '.') &&
1840       (separator != '-') &&
1841       (separator != ' '))
1842     return FALSE;
1843
1844   // separate the strings
1845   str1 = (unsigned char *) temp;
1846   while(*str1 != separator) str1++;
1847   str2 = str1 + 1;
1848   *str1 = 0;
1849   str1= (unsigned char *) temp;
1850
1851   // check len of the network portion
1852   if (strlen((char *) str1) != 8) return FALSE;
1853
1854   // check len of mac portion
1855   if (strlen((char *) str2) != 12) return FALSE;
1856
1857   // ok we like then lens, make sure that all chars are 0-f
1858   // check out the net id
1859   tmp = str1;
1860   while(*tmp != 0)
1861     if (((*tmp >= '0') && (*tmp <= '9'))||   // good 0-9
1862         ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
1863       tmp++;
1864     else
1865       return FALSE;
1866
1867   // check out the MAC address
1868   tmp = str2;
1869   while(*tmp != 0)
1870     if (((*tmp >= '0') && (*tmp <= '9'))||   // good 0-9
1871         ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
1872       tmp++;
1873     else
1874       return FALSE;
1875
1876   // convert to target string
1877   tmp = str1;
1878   while (*tmp != 0)
1879   {
1880   if ((*tmp >= '0') && (*tmp <= '9'))
1881     *tmp = *tmp - (char unsigned )'0';
1882   else
1883     *tmp = *tmp - (char unsigned) 'a' + (char unsigned) 10;
1884   tmp++;
1885   }
1886
1887   // network id portion
1888   address_buffer[0] = (str1[0]*16) + str1[1];
1889   address_buffer[1] = (str1[2]*16) + str1[3];
1890   address_buffer[2] = (str1[4]*16) + str1[5];
1891   address_buffer[3] = (str1[6]*16) + str1[7];
1892
1893   tmp = str2;
1894   while (*tmp != 0)
1895   {
1896   if ((*tmp >= '0') && (*tmp <= '9'))
1897     *tmp = *tmp - (char unsigned) '0';
1898   else
1899     *tmp = *tmp - (char unsigned) 'a'+ (char unsigned) 10;
1900   tmp++;
1901   }
1902
1903   address_buffer[4] = (str2[0]*16)  + str2[1];
1904   address_buffer[5] = (str2[2]*16)  + str2[3];
1905   address_buffer[6] = (str2[4]*16)  + str2[5];
1906   address_buffer[7] = (str2[6]*16)  + str2[7];
1907   address_buffer[8] = (str2[8]*16)  + str2[9];
1908   address_buffer[9] = (str2[10]*16) + str2[11];
1909
1910   return TRUE;
1911 }
1912
1913 //----[ IPX address format output ]-------------------------------------
1914 void IpxAddress::format_output() const
1915 {
1916   if (valid_flag)
1917     sprintf((char *) output_buffer,
1918             "%02x%02x%02x%02x%c%02x%02x%02x%02x%02x%02x",
1919             address_buffer[0],address_buffer[1],
1920             address_buffer[2],address_buffer[3],'-',
1921             address_buffer[4],address_buffer[5],
1922             address_buffer[6],address_buffer[7],
1923             address_buffer[8],address_buffer[9]);
1924   else
1925     *(char*)output_buffer = 0;
1926   IpxAddress *nc_this = PP_CONST_CAST(IpxAddress*, this);
1927   nc_this->addr_changed = false;
1928 }
1929
1930
1931 #ifdef _MAC_ADDRESS
1932 // get the host id portion of an ipx address
1933 int IpxAddress::get_hostid(MacAddress& mac) const
1934 {
1935    if (valid_flag)
1936    {
1937        char buffer[18];
1938        sprintf(buffer,"%02x:%02x:%02x:%02x:%02x:%02x", address_buffer[4],
1939                 address_buffer[5], address_buffer[6], address_buffer[7],
1940                 address_buffer[8], address_buffer[9]);
1941        MacAddress temp(buffer);
1942        mac = temp;
1943        if (mac.valid())
1944          return TRUE;
1945    }
1946    return FALSE;
1947 }
1948 #endif // function that needs _MAC_ADDRESS
1949
1950 //========================================================================
1951 //======== IpxSockAddress Implementation =================================
1952 //========================================================================
1953
1954 //----------[ constructor no args ]--------------------------------------
1955 IpxSockAddress::IpxSockAddress() : IpxAddress()
1956 {
1957   // always initialize SMI info
1958   smival.syntax = sNMP_SYNTAX_OCTETS;
1959   smival.value.string.len = IPXSOCKLEN;
1960   smival.value.string.ptr = address_buffer;
1961
1962   set_socket(0);
1963   addr_changed = true;
1964 }
1965
1966 //-----------[ construct an IpxSockAddress with another IpxSockAddress]----
1967 IpxSockAddress::IpxSockAddress(const IpxSockAddress &ipxaddr)
1968   : IpxAddress(ipxaddr)
1969 {
1970   // always initialize SMI info
1971   smival.syntax = sNMP_SYNTAX_OCTETS;
1972   smival.value.string.len = IPXSOCKLEN;
1973   smival.value.string.ptr = address_buffer;
1974
1975   // copy the socket value
1976   set_socket(ipxaddr.get_socket());
1977   addr_changed = true;
1978 }
1979
1980
1981 //---------------[ construct a IpxSockAddress from a string ]--------------
1982 IpxSockAddress::IpxSockAddress(const char *inaddr):IpxAddress()
1983 {
1984   // always initialize SMI info
1985   smival.syntax = sNMP_SYNTAX_OCTETS;
1986   smival.value.string.len = IPXSOCKLEN;
1987   smival.value.string.ptr = address_buffer;
1988
1989   valid_flag = parse_address(inaddr);
1990   addr_changed = true;
1991 }
1992
1993
1994 //---------------[ construct a IpxSockAddress from a GenAddress ]----------
1995 IpxSockAddress::IpxSockAddress(const GenAddress &genaddr):IpxAddress()
1996 {
1997   // always initialize SMI info
1998   smival.syntax = sNMP_SYNTAX_OCTETS;
1999   smival.value.string.len = IPXSOCKLEN;
2000   smival.value.string.ptr = address_buffer;
2001
2002   valid_flag = false;
2003   unsigned short socketid = 0;
2004   // allow use of an ipx or ipxsock address
2005   if ((genaddr.get_type() == type_ipx) )
2006   {
2007     valid_flag = genaddr.valid();
2008     if (valid_flag)
2009     {
2010       // copy in the Ipx address data
2011       IpxAddress temp_ipx((const char *) genaddr);
2012       *this = temp_ipx;
2013     }
2014   }
2015   else if ((genaddr.get_type() == type_ipxsock) )
2016   {
2017     valid_flag = genaddr.valid();
2018     if (valid_flag)
2019     {
2020       // copy in the Ipx address data
2021       IpxSockAddress temp_ipxsock((const char *) genaddr);
2022       *this = temp_ipxsock;
2023       //  socketid info since are making an IpxSockAddress
2024       socketid = temp_ipxsock.get_socket();
2025     }
2026   }
2027   set_socket(socketid);
2028   addr_changed = true;
2029 }
2030
2031 //------------[ construct an IpxSockAddress from a IpxAddress ]--------------
2032 IpxSockAddress::IpxSockAddress(const IpxAddress &ipxaddr):IpxAddress(ipxaddr)
2033 {
2034   // always initialize SMI info
2035   smival.syntax = sNMP_SYNTAX_OCTETS;
2036   smival.value.string.len = IPXSOCKLEN;
2037   smival.value.string.ptr = address_buffer;
2038
2039   set_socket(0);
2040   addr_changed = true;
2041 }
2042
2043 // copy an instance of this Value
2044 SnmpSyntax& IpxSockAddress::operator=(const SnmpSyntax &val)
2045 {
2046   if (this == &val) return *this; // protect against assignment from itself
2047
2048   valid_flag = false;              // will set to TRUE if really valid
2049   if (val.valid()){
2050     switch (val.get_syntax()){
2051     case sNMP_SYNTAX_OCTETS:
2052       {
2053         // See if it is of the Ipx address family
2054         // This handles IpxSockAddress == IpxAddress
2055         IpxSockAddress temp_ipx(val.get_printable());
2056         if (temp_ipx.valid()){
2057           *this = temp_ipx;                // ipxsock = ipxsock
2058         }
2059         // See if it is an OctetStr of appropriate length
2060         else if (((IpxSockAddress &)val).smival.value.string.len == IPXSOCKLEN){
2061           MEMCPY(address_buffer,
2062                  ((IpxSockAddress &)val).smival.value.string.ptr,
2063                  IPXSOCKLEN);
2064           valid_flag = true;
2065         }
2066       }
2067       break;
2068     }
2069   }
2070   addr_changed = true;
2071   return *this;
2072 }
2073
2074 // assignment to another IpAddress object overloaded
2075 IpxSockAddress& IpxSockAddress::operator=(const IpxSockAddress &ipxaddr)
2076 {
2077   if (this == &ipxaddr) return *this; // protect against assignment from itself
2078
2079   (IpxAddress&)*this = ipxaddr;         // use ancestor assignment for ipx addr
2080   set_socket(ipxaddr.get_socket());        // copy socket value
2081   addr_changed = true;
2082   return *this;
2083 }
2084
2085 //----[ IPX address format output ]-------------------------------------
2086 void IpxSockAddress::format_output() const
2087 {
2088   IpxAddress::format_output(); // allow ancestors to format their buffers
2089
2090   if (valid_flag)
2091     sprintf((char *) output_buffer,"%s/%d",
2092             IpxAddress::get_printable(), get_socket());
2093   else
2094     *(char*)output_buffer = 0;
2095   IpxSockAddress *nc_this = PP_CONST_CAST(IpxSockAddress*, this);
2096   nc_this->addr_changed = false;
2097 }
2098
2099 //-----[ IP Address parse Address ]---------------------------------
2100 bool IpxSockAddress::parse_address(const char *inaddr)
2101 {
2102    char buffer[MAX_FRIENDLY_NAME];
2103    unsigned short socketid=0;
2104
2105    if (inaddr && (strlen(inaddr)< MAX_FRIENDLY_NAME))
2106      strcpy(buffer, inaddr);
2107    else
2108    {
2109      valid_flag = false;
2110      return FALSE;
2111    }
2112    // look for port info @ the end of the string
2113    // port can be delineated by a ':' or a '/'
2114    // if neither are present then just treat it
2115    // like a normal IpAddress
2116    char *tmp;
2117    tmp = strstr(buffer,"/");
2118
2119    if (tmp != NULL)
2120    {
2121      *tmp=0;   // new null terminator
2122      tmp++;
2123      socketid = atoi(tmp);
2124    }
2125    set_socket(socketid);
2126    return IpxAddress::parse_address(buffer);
2127 }
2128
2129
2130
2131 //-------------[ set the socket number ]----------------------------------
2132 void IpxSockAddress::set_socket(const unsigned short s)
2133 {
2134   unsigned short sock_nbo = htons(s);
2135   MEMCPY(&address_buffer[IPXLEN], &sock_nbo, 2);
2136   addr_changed = true;
2137 }
2138
2139 //--------------[ get the socket number ]---------------------------------
2140 unsigned short IpxSockAddress::get_socket() const
2141 {
2142   if (valid_flag)
2143   {
2144     unsigned short sock_nbo;
2145     MEMCPY(&sock_nbo, &address_buffer[IPXLEN], 2);
2146     return ntohs(sock_nbo);
2147   }
2148   return 0; // don't use uninitialized memory
2149 }
2150 #endif // _IPX_ADDRESS
2151
2152 #ifdef _MAC_ADDRESS
2153 //========================================================================
2154 //======== MACAddress Implementation =====================================
2155 //========================================================================
2156
2157 //--------[ constructor, no arguments ]-----------------------------------
2158 MacAddress::MacAddress() : Address()
2159 {
2160   // always initialize SMI info
2161   smival.syntax = sNMP_SYNTAX_OCTETS;
2162   smival.value.string.len = MACLEN;
2163   smival.value.string.ptr = address_buffer;
2164
2165   valid_flag = false;
2166   addr_changed = true;
2167 }
2168
2169 //-----[ MAC Address copy constructor ]---------------------------------
2170 MacAddress::MacAddress(const MacAddress &macaddr)
2171 {
2172   // always initialize SMI info
2173   smival.syntax = sNMP_SYNTAX_OCTETS;
2174   smival.value.string.len = MACLEN;
2175   smival.value.string.ptr = address_buffer;
2176
2177   valid_flag = macaddr.valid_flag;
2178   if (valid_flag)
2179     MEMCPY(address_buffer, macaddr.address_buffer, MACLEN);
2180   addr_changed = true;
2181 }
2182
2183 //---------[ constructor with a string argument ]-------------------------
2184 MacAddress::MacAddress(const char  *inaddr):Address()
2185 {
2186   // always initialize SMI info
2187   smival.syntax = sNMP_SYNTAX_OCTETS;
2188   smival.value.string.len = MACLEN;
2189   smival.value.string.ptr = address_buffer;
2190
2191   valid_flag = parse_address(inaddr);
2192   addr_changed = true;
2193 }
2194
2195 //-----[ construct a MacAddress from a GenAddress ]------------------------
2196 MacAddress::MacAddress(const GenAddress &genaddr)
2197 {
2198   // always initialize SMI info
2199   smival.syntax = sNMP_SYNTAX_OCTETS;
2200   smival.value.string.len = MACLEN;
2201   smival.value.string.ptr = address_buffer;
2202
2203   valid_flag = false;
2204   // allow use of mac address
2205   if (genaddr.get_type() == type_mac)
2206   {
2207     valid_flag = genaddr.valid();
2208     if (valid_flag)
2209     {
2210       // copy in the Mac address data
2211       *this = genaddr.cast_macaddress();
2212     }
2213   }
2214   addr_changed = true;
2215 }
2216
2217 //------[ assignment to another ipaddress object overloaded ]--------------
2218 MacAddress& MacAddress::operator=(const MacAddress &macaddress)
2219 {
2220   if (this == &macaddress) return *this;// protect against assignment from self
2221
2222   valid_flag = macaddress.valid_flag;
2223   if (valid_flag)
2224     MEMCPY(address_buffer, macaddress.address_buffer, MACLEN);
2225   addr_changed = true;
2226   return *this;
2227 }
2228
2229
2230
2231 //-----[ MAC Address general = operator ]---------------------------------
2232 SnmpSyntax& MacAddress::operator=(const SnmpSyntax &val)
2233 {
2234   if (this == &val) return *this;  // protect against assignment from itself
2235
2236   valid_flag = false;              // will set to TRUE if really valid
2237   if (val.valid())
2238   {
2239     switch (val.get_syntax())
2240     {
2241       case sNMP_SYNTAX_OCTETS:
2242         if (((MacAddress &)val).smival.value.string.len == MACLEN)
2243         {
2244           MEMCPY(address_buffer, ((MacAddress &)val).smival.value.string.ptr,
2245                  MACLEN);
2246           valid_flag = true;
2247         }
2248         break;
2249     }
2250   }
2251   addr_changed = true;
2252   return *this;
2253 }
2254
2255 //-----[ MAC Address parse Address ]--------------------------------------
2256 // Convert a string to a six byte MAC address
2257 // On success sets validity TRUE or FALSE
2258 //
2259 //     MAC address format
2260 //
2261 //   MAC ADDRESS
2262 //   01 02 03 04 05 06
2263 //   XX:XX:XX:XX:XX:XX
2264 //   Valid input format
2265 //
2266 //   XXXXXXXXXXXX
2267 //   Total length must be 17
2268 //   Each char must take on value 0-F
2269 //
2270 //
2271 bool MacAddress::parse_address(const char *inaddr)
2272 {
2273   char temp[30];    // don't destroy original
2274   char unsigned *tmp;
2275   size_t z;
2276
2277   // save the orginal source
2278   if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
2279   strcpy(temp, inaddr);
2280   trim_white_space(temp);
2281
2282   // bad total length check
2283   if (strlen(temp) != 17)
2284      return FALSE;
2285
2286   // check for colons
2287   if ((temp[2] != ':')||(temp[5] != ':')||(temp[8]!=':')||(temp[11]!=':')||(temp[14] !=':'))
2288      return FALSE;
2289
2290   // strip off the colons
2291   tmp = (unsigned char *) temp;
2292   int i = 0;
2293   while (*tmp != 0)
2294   {
2295      if (*tmp != ':')
2296      {
2297         temp[i] = *tmp;
2298         i++;
2299      }
2300      tmp++;
2301   }
2302   temp[i] = 0;
2303
2304   // convert to lower
2305   for(z=0;z<strlen(temp);z++)
2306      temp[z] = tolower(temp[z]);
2307
2308
2309   // check out the MAC address
2310   tmp = (unsigned char *) temp;
2311   while(*tmp != 0)
2312     if (((*tmp >= '0') && (*tmp <= '9'))||   // good 0-9
2313         ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
2314       tmp++;
2315     else
2316       return FALSE;
2317
2318   // convert to target string
2319   tmp = (unsigned char *) temp;
2320   while (*tmp != 0)
2321   {
2322   if ((*tmp >= '0') && (*tmp <= '9'))
2323     *tmp = *tmp - (char unsigned )'0';
2324   else
2325     *tmp = *tmp - (char unsigned) 'a' + (char unsigned) 10;
2326   tmp++;
2327   }
2328
2329   address_buffer[0] =  (temp[0]*16) + temp[1];
2330   address_buffer[1] =  (temp[2]*16) + temp[3];
2331   address_buffer[2] =  (temp[4]*16) + temp[5];
2332   address_buffer[3] =  (temp[6]*16) + temp[7];
2333   address_buffer[4] =  (temp[8]*16) + temp[9];
2334   address_buffer[5] =  (temp[10]*16) + temp[11];
2335
2336   return TRUE;
2337 }
2338
2339 //----[ MAC address format output ]---------------------------------
2340 void MacAddress::format_output() const
2341 {
2342   if (valid_flag)
2343     sprintf((char*)output_buffer,"%02x:%02x:%02x:%02x:%02x:%02x",
2344             address_buffer[0], address_buffer[1], address_buffer[2],
2345             address_buffer[3], address_buffer[4], address_buffer[5]);
2346   else
2347     *(char*)output_buffer = 0;
2348   MacAddress *nc_this = PP_CONST_CAST(MacAddress*, this);
2349   nc_this->addr_changed = false;
2350 }
2351
2352 unsigned int MacAddress::hashFunction() const
2353 {
2354   return ((((address_buffer[0] << 8) + address_buffer[1]) * HASH0)
2355         + (((address_buffer[2] << 8) + address_buffer[3]) * HASH1)
2356         + (((address_buffer[4] << 8) + address_buffer[5]) * HASH2));
2357 }
2358 #endif // _MAC_ADDRESS
2359
2360 //========================================================================
2361 //========== Generic Address Implementation ==============================
2362 //========================================================================
2363
2364 //-----------[ constructor, no arguments ]--------------------------------
2365 GenAddress::GenAddress() : Address()
2366 {
2367   ADDRESS_TRACE;
2368
2369   // initialize SMI info
2370   // BOK: this is generally not used for GenAddress,
2371   // but we need this to be a replica of the real address'
2372   // smival info so that operator=SnmpSyntax will work.
2373   smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
2374   smival.value.string.len = 0;                        // to be overridden
2375   smival.value.string.ptr = address_buffer;        // constant
2376
2377   valid_flag = false;
2378   address = 0;
2379   output_buffer[0] = 0;
2380 }
2381
2382 //-----------[ constructor with a string argument ]----------------------
2383 GenAddress::GenAddress(const char  *addr,
2384                        const Address::addr_type use_type)
2385 {
2386   ADDRESS_TRACE;
2387
2388   // initialize SMI info
2389   // BOK: smival is generally not used for GenAddress, but
2390   //      we need this to be a replica of the real address'
2391   //      smival info so that <class>::operator=SnmpSyntax
2392   //      will work.
2393   smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
2394   smival.value.string.len = 0;                        // to be overridden
2395   smival.value.string.ptr = address_buffer;        // constant
2396
2397   address = 0;
2398   parse_address(addr, use_type);
2399
2400   // Copy real address smival info into GenAddr smival
2401   // BOK: smival is generally not used for GenAddress, but
2402   //      we need this to be a replica of the real address'
2403   //      smival info so that <class>::operator=SnmpSyntax
2404   //      will work.
2405   if (valid_flag ) {
2406       smival.syntax = ((GenAddress *)address)->smival.syntax;
2407       smival.value.string.len =
2408           ((GenAddress *)address)->smival.value.string.len;
2409       memcpy(smival.value.string.ptr,
2410           ((GenAddress *)address)->smival.value.string.ptr,
2411           (size_t)smival.value.string.len);
2412   }
2413   output_buffer[0] = 0;
2414 }
2415
2416 //-----------[ constructor with an Address argument ]--------------------
2417 GenAddress::GenAddress(const Address &addr)
2418 {
2419   ADDRESS_TRACE;
2420
2421   output_buffer[0] = 0;
2422   // initialize SMI info
2423   // BOK: this is generally not used for GenAddress,
2424   // but we need this to be a replica of the real address'
2425   // smival info so that operator=SnmpSyntax will work.
2426   smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
2427   smival.value.string.len = 0;                        // to be overridden
2428   smival.value.string.ptr = address_buffer;        // constant
2429
2430   valid_flag = false;
2431   // make sure that the object is valid
2432   if (!addr.valid()) {
2433     address = 0;
2434     return;
2435   }
2436
2437   // addr can be a GenAddress object and calling clone() on that is bad...
2438   if (addr.is_gen_address())
2439     address = (Address *)(((const GenAddress&)addr).address->clone());
2440   else
2441     address = (Address*)addr.clone();
2442
2443   if (address)
2444     valid_flag = address->valid();
2445
2446   // Copy real address smival info into GenAddr smival
2447   // BOK: smival is generally not used for GenAddress, but
2448   //      we need this to be a replica of the real address'
2449   //      smival info so that <class>::operator=SnmpSyntax
2450   //      will work.
2451   if (valid_flag )
2452   {
2453     smival.syntax = address->get_syntax();
2454     smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
2455     memcpy(smival.value.string.ptr,
2456            ((GenAddress *)address)->smival.value.string.ptr,
2457            (size_t)smival.value.string.len);
2458   }
2459 }
2460
2461 //-----------------[ constructor with another GenAddress object ]-------------
2462 GenAddress::GenAddress(const GenAddress &addr)
2463 {
2464   ADDRESS_TRACE;
2465
2466   output_buffer[0] = 0;
2467   // initialize SMI info
2468   // BOK: this is generally not used for GenAddress,
2469   // but we need this to be a replica of the real address'
2470   // smival info so that operator=SnmpSyntax will work.
2471   smival.syntax = sNMP_SYNTAX_OCTETS;
2472   smival.value.string.len = 0;
2473   smival.value.string.ptr = address_buffer;
2474
2475   valid_flag = false;
2476   // make sure that the object is valid
2477   if (!addr.valid_flag)
2478   {
2479     address = 0;
2480     return;
2481   }
2482
2483   address = (Address *)addr.address->clone();
2484   if (address)
2485     valid_flag = address->valid();
2486
2487   // Copy real address smival info into GenAddr smival
2488   // BOK: smival is generally not used for GenAddress, but
2489   //      we need this to be a replica of the real address'
2490   //      smival info so that <class>::operator=SnmpSyntax
2491   //      will work.
2492   if (valid_flag )
2493   {
2494     smival.syntax = ((GenAddress *)address)->smival.syntax;
2495     smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
2496     memcpy(smival.value.string.ptr,
2497            ((GenAddress *)address)->smival.value.string.ptr,
2498            (size_t)smival.value.string.len);
2499   }
2500 }
2501
2502 //------[ assignment GenAddress = GenAddress ]-----------------------------
2503 GenAddress& GenAddress::operator=(const GenAddress &addr)
2504 {
2505   ADDRESS_TRACE;
2506
2507   if (this == &addr) return *this;  // protect against assignment from itself
2508
2509   valid_flag = false;
2510   if (address)
2511   {
2512     delete address;
2513     address = 0;
2514   }
2515   if (addr.address)
2516     address = (Address *)(addr.address->clone());
2517   if (address)
2518     valid_flag = address->valid();
2519
2520   // Copy real address smival info into GenAddr smival
2521   // BOK: smival is generally not used for GenAddress, but
2522   //      we need this to be a replica of the real address'
2523   //      smival info so that <class>::operator=SnmpSyntax
2524   //      will work.
2525   if (valid_flag )
2526   {
2527     smival.syntax = ((GenAddress *)address)->smival.syntax;
2528     smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
2529     memcpy(smival.value.string.ptr,
2530            ((GenAddress *)address)->smival.value.string.ptr,
2531            (size_t)smival.value.string.len);
2532   }
2533
2534   return *this;
2535 }
2536
2537 //------[ assignment GenAddress = Address ]--------------------------------
2538 GenAddress& GenAddress::operator=(const Address &addr)
2539 {
2540   ADDRESS_TRACE;
2541
2542   if (this == &addr) return *this;  // protect against assignment from itself
2543
2544   valid_flag = false;
2545   if (address)
2546   {
2547     delete address;
2548     address = 0;
2549   }
2550
2551   // addr can be a GenAddress object and calling clone() on that is bad...
2552   if (addr.is_gen_address())
2553     address = (Address *)(((const GenAddress&)addr).address->clone());
2554   else
2555     address = (Address*)addr.clone();
2556
2557   if (address)
2558     valid_flag = address->valid();
2559
2560   // Copy real address smival info into GenAddr smival
2561   // BOK: smival is generally not used for GenAddress, but
2562   //      we need this to be a replica of the real address'
2563   //      smival info so that <class>::operator=SnmpSyntax
2564   //      will work.
2565   if (valid_flag )
2566   {
2567     smival.syntax = ((GenAddress *)address)->smival.syntax;
2568     smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
2569     memcpy(smival.value.string.ptr,
2570            ((GenAddress *)address)->smival.value.string.ptr,
2571            (size_t)smival.value.string.len);
2572   }
2573
2574   return *this;
2575 }
2576
2577
2578 //------[ assignment GenAddress = any SnmpSyntax ]-----------------------
2579 SnmpSyntax& GenAddress::operator=(const SnmpSyntax &val)
2580 {
2581   ADDRESS_TRACE;
2582
2583   if (this == &val) return *this; // protect against assignment from itself
2584
2585   valid_flag = false;             // will get set to TRUE if really valid
2586   if (address)
2587   {
2588     delete address;
2589     address = 0;
2590   }
2591
2592   if (val.valid())
2593   {
2594     switch (val.get_syntax() )
2595     {
2596       //-----[ ip address case ]-------------
2597       // BOK: this case shouldn't be needed since there is an explicit
2598       // GenAddr=Address assignment that will override this assignment.
2599       // Left here for posterity.
2600       case sNMP_SYNTAX_IPADDR:
2601       {
2602         address = new IpAddress(val.get_printable());
2603         if (address)
2604           valid_flag = address->valid();
2605       }
2606       break;
2607
2608       //-----[ udp address case ]------------
2609       //-----[ ipx address case ]------------
2610       //-----[ mac address case ]------------
2611       // BOK:  This is here only to support GenAddr = primitive OctetStr.
2612       // The explicit GenAddr=Address assignment will handle the cases
2613       // GenAddr = [UdpAdd|IpxAddr|IpxSock|MacAddr].
2614       // Note, using the heuristic of octet str len to determine type of
2615       // address to create is not accurate when address lengths are equal
2616       // (e.g., UDPIPLEN == MACLEN).  It gets worse if we add AppleTalk or
2617       // OSI which use variable length addresses!
2618       case sNMP_SYNTAX_OCTETS:
2619       {
2620         unsigned long val_len;
2621         val_len = ((GenAddress &)val).smival.value.string.len;
2622
2623         if ((val_len == UDPIPLEN) || IS_UDPIP6LEN(val_len))
2624           address = new UdpAddress;
2625         else if ((val_len == IPLEN) || IS_IP6LEN(val_len))
2626           address = new IpAddress;
2627 #ifdef _IPX_ADDRESS
2628         else if (val_len == IPXLEN)
2629           address = new IpxAddress;
2630         else if (val_len == IPXSOCKLEN)
2631           address = new IpxSockAddress;
2632 #endif
2633 #ifdef _MAC_ADDRESS
2634         else  if (val_len == MACLEN)
2635           address = new MacAddress;
2636 #endif
2637
2638         if (address)
2639         {
2640           *address = val;
2641           valid_flag = address->valid();
2642         }
2643       }
2644       break;
2645     }   // end switch
2646   }
2647
2648   // Copy real address smival info into GenAddr smival
2649   // BOK: smival is generally not used for GenAddress, but
2650   //      we need this to be a replica of the real address'
2651   //      smival info so that <class>::operator=SnmpSyntax
2652   //      will work.
2653   if (valid_flag )
2654   {
2655     smival.syntax = ((GenAddress *)address)->smival.syntax;
2656     smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
2657     memcpy(smival.value.string.ptr,
2658            ((GenAddress *)address)->smival.value.string.ptr,
2659            (size_t)smival.value.string.len);
2660   }
2661
2662   return *this;
2663 }
2664
2665
2666 // redefined parse address for macs
2667 bool GenAddress::parse_address(const char *addr,
2668                                const Address::addr_type use_type)
2669 {
2670   ADDRESS_TRACE;
2671
2672   if (address) delete address;
2673
2674   // try to create each of the addresses until the correct one
2675   // is found
2676
2677   //BOK: Need to try IPX Sock and IPX before UDP since on Win32,
2678   //     gethostbyname() seems to think the ipx network number
2679   //     portion is a valid ipaddress string... stupid WinSOCK!
2680
2681 #ifdef _IPX_ADDRESS
2682   if ((use_type == Address::type_invalid) ||
2683       (use_type == Address::type_ipxsock))
2684   {
2685     // ipxsock address
2686     address = new IpxSockAddress(addr);
2687     valid_flag = address->valid();
2688     if (valid_flag && ((IpxSockAddress*)address)->get_socket())
2689       return TRUE;   // ok its an ipxsock address
2690
2691     delete address;  // otherwise delete it and try another
2692   }
2693
2694   if ((use_type == Address::type_invalid) ||
2695       (use_type == Address::type_ipx))
2696   {
2697     // ipx address
2698     address = new IpxAddress(addr);
2699     valid_flag = address->valid();
2700     if (valid_flag)
2701       return TRUE;   // ok its an ipx address
2702
2703     delete address;  // otherwise delete it and try another
2704   }
2705 #endif // _IPX_ADDRESS
2706
2707   //TM: Must try the derived classes first...one pitfall of the
2708   //following solution is if someone creates with a port/socket of 0 the
2709   //class will get demoted to ip/ipx.  The only proper way to do this is
2710   //to parse the strings ourselves.
2711
2712   if ((use_type == Address::type_invalid) ||
2713       (use_type == Address::type_udp))
2714   {
2715     // udp address
2716     address = new UdpAddress(addr);
2717     valid_flag = address->valid();
2718     if (valid_flag && ((UdpAddress*)address)->get_port())
2719       return TRUE;       // ok its a udp address
2720
2721     delete address;  // otherwise delete it and try another
2722   }
2723
2724   if ((use_type == Address::type_invalid) ||
2725       (use_type == Address::type_ip))
2726   {
2727     // ip address
2728     address = new IpAddress(addr);
2729     valid_flag = address->valid();
2730     if (valid_flag)
2731       return TRUE;       // ok its an ip address
2732
2733     delete address;   // otherwise delete it and try another
2734   }
2735
2736 #ifdef _MAC_ADDRESS
2737   if ((use_type == Address::type_invalid) ||
2738       (use_type == Address::type_mac))
2739   {
2740     // mac address
2741     address = new MacAddress(addr);
2742     valid_flag = address->valid();
2743     if (valid_flag)
2744       return TRUE;    // ok, its a mac
2745
2746     delete address;  // otherwise its invalid
2747   }
2748 #endif // _MAC_ADDRESS
2749
2750   address = 0;
2751   return FALSE;
2752 }
2753
2754 #ifdef SNMP_PP_NAMESPACE
2755 }; // end of namespace Snmp_pp
2756 #endif