Merge branch 'release-2.140.131' into dev
[feisty_meow.git] / octopi / library / sockets / machine_uid.cpp
1 /*****************************************************************************\
2 *                                                                             *
3 *  Name   : machine_uid                                                       *
4 *  Author : Chris Koeritz                                                     *
5 *                                                                             *
6 *******************************************************************************
7 * Copyright (c) 2000-$now By Author.  This program is free software; you can  *
8 * redistribute it and/or modify it under the terms of the GNU General Public  *
9 * License as published by the Free Software Foundation; either version 2 of   *
10 * the License or (at your option) any later version.  This is online at:      *
11 *     http://www.fsf.org/copyleft/gpl.html                                    *
12 * Please send any updates to: fred@gruntose.com                               *
13 \*****************************************************************************/
14
15 //#include "internet_address.h"
16 #include "machine_uid.h"
17
18 #include <basis/byte_array.h>
19 #include <basis/functions.h>
20 #include <basis/astring.h>
21 #include <basis/mutex.h>
22 #include <structures/checksums.h>
23 #include <structures/object_packers.h>
24 #include <structures/static_memory_gremlin.h>
25 #include <textual/byte_formatter.h>
26
27 using namespace basis;
28 using namespace structures;
29 using namespace textual;
30
31 namespace sockets {
32
33 machine_uid::machine_uid()
34 : _contents(new byte_array)
35 { *_contents += abyte(INVALID_LOCATION); }
36
37 machine_uid::machine_uid(known_location_types type,
38     const byte_array &address)
39 : _contents(new byte_array)
40 {
41   *_contents += abyte(type); 
42   *_contents += address;
43 }
44
45 machine_uid::machine_uid(const machine_uid &to_copy)
46 : packable(),
47   _contents(new byte_array)
48 { *this = to_copy; }
49
50 machine_uid::~machine_uid() { WHACK(_contents); }
51
52 void machine_uid::reset(known_location_types type, const byte_array &address)
53 {
54   _contents->reset();
55   *_contents += abyte(type); 
56   *_contents += address;
57 }
58
59 const byte_array &machine_uid::raw() const { return *_contents; }
60
61 const astring &machine_uid::type_name(known_location_types type)
62 {
63   static astring TCPIP_NAME = "TCPIP";
64   static astring IPX_NAME = "IPX";
65   static astring NETBIOS_NAME = "NETBIOS";
66   static astring UNKNOWN_NAME = "INVALID";
67
68   switch (type) {
69     case TCPIP_LOCATION: return TCPIP_NAME;
70     case IPX_LOCATION: return IPX_NAME;
71     case NETBIOS_LOCATION: return NETBIOS_NAME;
72     default: return UNKNOWN_NAME;
73   }
74 }
75
76 machine_uid &machine_uid::operator = (const machine_uid &to_copy)
77 {
78   if (this == &to_copy) return *this;
79   *_contents = *to_copy._contents;
80   return *this;
81 }
82
83 astring machine_uid::text_form() const
84 {
85   astring to_return;
86   to_return += type_name(type()) + "[";
87   for (int i = 1; i < _contents->length(); i++) {
88     if (type() == TCPIP_LOCATION)
89       to_return += a_sprintf("%d", int(_contents->get(i)));
90     else
91       to_return += a_sprintf("%02x", int(_contents->get(i)));
92     if (i < _contents->length() - 1)
93       to_return += ".";
94   }
95   to_return += "]";
96   return to_return;
97 }
98
99 astring machine_uid::compact_form() const
100 {
101   astring to_return;
102   byte_formatter::bytes_to_shifted_string(*_contents, to_return);
103   return to_return;
104 }
105
106 machine_uid machine_uid::expand(const astring &compacted)
107 {
108   machine_uid to_return;
109   to_return._contents->reset();
110   byte_formatter::shifted_string_to_bytes(compacted, *to_return._contents);
111   return to_return;
112 }
113
114 bool machine_uid::operator == (const machine_uid &to_compare) const
115 {
116   // an empty id is only equal to another empty id.
117   if (!_contents->length() || !to_compare._contents->length())
118     return !_contents->length() && !to_compare._contents->length();
119   if (_contents->length() != to_compare._contents->length()) return false;
120   for (int i = 0; i < _contents->length(); i++)
121     if (_contents->get(i) != to_compare._contents->get(i)) return false;
122   return true;
123 }
124
125 machine_uid::known_location_types machine_uid::type() const
126 {
127   if (!_contents->length()) return INVALID_LOCATION;
128   return known_location_types(_contents->get(0));
129 }
130
131 int machine_uid::packed_size() const
132 {
133   return PACKED_SIZE_INT32 + _contents->length();
134 }
135
136 void machine_uid::pack(byte_array &packed_form) const
137 {
138   structures::attach(packed_form, _contents->length());
139   packed_form += *_contents;
140 }
141
142 bool machine_uid::unpack(byte_array &packed_form)
143 {
144   int len = 0;
145   if (!structures::detach(packed_form, len)) return false;
146     // there's no length even?
147   if (packed_form.length() < len) return false;
148     // not enough size left for the length specified.
149   *_contents = packed_form.subarray(0, len - 1);
150   packed_form.zap(0, len - 1);
151   return true;
152 }
153
154 byte_array machine_uid::native() const
155 {
156   if (_contents->length() <= 1) return byte_array();  // invalid.
157   return _contents->subarray(1, _contents->last());
158 }
159
160 //////////////
161
162 class internal_machine_uid_array : public array<machine_uid> {};
163
164 machine_uid_array::machine_uid_array()
165 : _uids(new internal_machine_uid_array)
166 {}
167
168 machine_uid_array::machine_uid_array(const machine_uid_array &to_copy)
169 : root_object(),
170   _uids(new internal_machine_uid_array(*to_copy._uids))
171 {
172 }
173
174 machine_uid_array::~machine_uid_array()
175 {
176   WHACK(_uids);
177 }
178
179 SAFE_STATIC_CONST(machine_uid_array, machine_uid_array::blank_array, )
180
181 machine_uid_array &machine_uid_array::operator =
182     (const machine_uid_array &to_copy)
183 {
184   if (this != &to_copy) {
185     *_uids = *to_copy._uids;
186   }
187   return *this;
188 }
189
190 bool machine_uid_array::operator += (const machine_uid &to_add)
191 {
192   if (member(to_add)) return false;
193   _uids->concatenate(to_add);
194   return true;
195 }
196
197 int machine_uid_array::elements() const { return _uids->length(); }
198
199 astring machine_uid_array::text_form() const
200 {
201   astring to_return;
202   for (int i = 0; i < _uids->length(); i++) {
203     to_return += _uids->get(i).text_form() + " ";
204   }
205   return to_return;
206 }
207
208 machine_uid &machine_uid_array::operator [] (int index)
209 { return _uids->use(index); }
210
211 const machine_uid &machine_uid_array::operator [] (int index) const
212 { return _uids->get(index); }
213
214 void machine_uid_array::reset() { _uids->reset(); }
215
216 bool machine_uid_array::member(const machine_uid &to_test) const
217 {
218   const int test_len = to_test.raw().length();
219   for (int i = 0; i < _uids->length(); i++) {
220     const machine_uid &curr = _uids->get(i);
221     // test for the length first since that's cheaper.
222     if ( (test_len == curr.raw().length()) && (curr == to_test) ) {
223       return true;
224     } else if (!to_test.valid() && !curr.valid()) return true;
225       // both are invalid, so the item to find is present.
226
227 /*
228       if (!to_test.valid() || !curr.valid()) continue;
229         // one is invalid but the other is not; not a match.
230 all bogus!
231 //hmmm: weird partial matching being allowed here.
232       bool to_return = true;  // assume it's good until told otherwise.
233       // if the first parts of the addresses agree, then assume we're
234       for (int j = 0; j < minimum(test_len, curr.raw().length()); j++) {
235         if (curr.raw().get(j) != to_test.raw().get(j)) {
236           to_return = false;
237         }
238       }
239       if (to_return)
240         return true;
241     }
242 */
243   }
244   return false;
245 }
246
247 //////////////
248
249 internet_machine_uid::internet_machine_uid(const astring &hostname,
250     const byte_array &ip_address)
251 {
252   byte_array addr(ip_address);
253   basis::un_short fletch = checksums::fletcher_checksum((const abyte *)hostname.observe(),
254       hostname.length());
255   structures::attach(addr, fletch);
256   reset(machine_uid::TCPIP_LOCATION, addr);
257 }
258
259 } //namespace.
260