feisty meow concerns codebase 2.140
internet_address.cpp
Go to the documentation of this file.
1
2// Name : internet_address
3// Author : Chris Koeritz
5// Copyright (c) 1995-$now By Author. This program is free software; you can
6// redistribute it and/or modify it under the terms of the GNU General Public
7// License as published by the Free Software Foundation:
8// http://www.gnu.org/licenses/gpl.html
9// or under the terms of the GNU Library license:
10// http://www.gnu.org/licenses/lgpl.html
11// at your preference. Those licenses describe your legal rights to this
12// software, and no other rights or warranties apply.
13// Please send updates for this code to: fred@gruntose.com -- Thanks, fred.
15
16#include "internet_address.h"
17#include "machine_uid.h"
18
19#include <basis/byte_array.h>
20#include <basis/functions.h>
21#include <basis/astring.h>
22#include <basis/mutex.h>
28#include <textual/parser_bits.h>
29
30#include <stdio.h>
31#include <string.h>
32
33using namespace basis;
34using namespace configuration;
35using namespace loggers;
36using namespace structures;
37using namespace textual;
38
39namespace sockets {
40
41//#define DEBUG_ADDRESS
42 // uncomment if you want a debugging version of address.
43
45
46#undef LOG
47#define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
48
50
51/*
52//hmmm: consider moving the functions for storage out to a helper file.
53
54internet_address internet_address::load(configurator &config,
55 const astring &section, const astring &name, const internet_address &def)
56{
57 astring token_list;
58 if (!config.get(section, name, token_list)) {
59 // no entry stored means no address. set the address to the default.
60 config.put(section, name, def.tokenize());
61 return def;
62 }
63 internet_address to_return;
64 // get the rest of the work done by detokenize.
65 if (to_return.detokenize(token_list)) return to_return;
66 // didn't work, dang it. Note that we don't reject it here and store the
67 // default. that's because this indicates an error in formatting of the
68 // address, and we want the user to have a chance to correct that and try
69 // again.
70 return internet_address();
71}
72
73bool internet_address::store(configurator &config, const astring &section,
74 const astring &name, const internet_address &to_store)
75{
76 astring text = to_store.tokenize();
77 return config.put(section, name, text);
78}
79*/
80
82
83// provides an easy way to cast to the proper type and provide a non-pointer
84// to work with.
85#define CAST_UP(type) \
86 const type *temp = dynamic_cast<const type *>(&compare_in); \
87 if (!temp) return false; /* shouldn't happen but it means bad things. */ \
88 const type &to_compare = *temp;
89
91
93
95 const astring &host, int port_in)
96{ fill(ip, host, port_in); }
97
98//hmmm: for ipv6, we will need a new object, called ipv6_address perhaps.
99// it will copy everything here but will have a longer address array.
100// we will need a new object for ipv6_machine_uid also.
101
104
106 astring &accum)
107{
108 FUNCDEF("ip_appropriate_number");
109 accum.reset();
110 for (int i = indy; (i < indy + 3) && (i < to_check.length()); i++) {
111 // make sure it looks like a good number.
112 if (!parser_bits::is_numeric(to_check[i]) || (to_check[i] == '-') ) {
113 // this one doesn't look good right here, but if we already got a digit,
114 // we're okay.
115 if (i == indy) return false; // hadn't gotten any digits at all yet.
116 else break; // got one, so let's check our progress below.
117 }
118 accum += to_check[i]; // snag the current digit.
119 }
120 if (!accum.length()) return false; // how would that happen?
121 int convert = accum.convert(-1);
122 return (convert >= 0) && (convert <= 255);
123}
124
125// needs to see 1-3 numbers, period, 1-3 numbers, period etc...
126// for a total of three periods and 4 number sets.
128 astring &ip_found)
129{
130 FUNCDEF("has_ip_address");
131 int nums_seen = 0;
132 ip_found.reset();
133 for (int i = 0; i < to_check.length(); i++) {
134 bool hosed = false;
135 astring num_found;
136// if (!!ip_found) LOG(astring("current ip found=") + ip_found);
137 if (!ip_appropriate_number(to_check, i, num_found)) {
138// LOG(a_sprintf("no ip approp %d", i));
139 hosed = true;
140 } else {
141 // we're seeing the number we want here.
142// LOG(astring("num found = ") + num_found);
143 nums_seen++;
144 if (nums_seen >= 4) {
145 ip_found += num_found; // get our last part.
146 return true; // hey, that's a match.
147 }
148 // look for a period now.
149 int period_indy = to_check.find('.', i);
150 if (negative(period_indy) || (period_indy > i + 3) ) hosed = true;
151 else {
152 for (int x = i; x < period_indy; x++) {
153 if (!parser_bits::is_numeric(to_check[x]) || (to_check[x] == '-')) {
154// LOG(a_sprintf("hosed by bad char at %d -> %c", x, to_check[x]));
155 hosed = true; // wrong character seen in between.
156 }
157 }
158 if (!hosed) {
159 ip_found += to_check.substring(i, period_indy);
160 i = period_indy; // skip to where our next number should be.
161 }
162 }
163 }
164 if (hosed) {
165 nums_seen = 0;
166 ip_found.reset();
167 }
168 }
169 return false;
170}
171
172const abyte localhosts_bytes[] = { 127, 0, 0, 1 };
174 (ADDRESS_SIZE, localhosts_bytes))
175
177{
178 // check whether the host is "local" or "localhost".
179 astring host = hostname;
180 host.to_lower();
181 if ( (host.equal_to("local")) || (host.equal_to("localhost")) )
182 return true;
183
184 // check whether the address is local even if the hostname wasn't.
185 for (int i = 0; i < ADDRESS_SIZE; i++) {
186 if (ip_address[i] != localhost().get(i))
187 return false;
188 }
189
190 return true; // the address matched.
191}
192
194{
195 // try the hostname first.
196 astring remote = hostname;
197 if (remote.t()) return remote;
198 // there was no host we can use; try the IP address instead.
200 remote = ip_address_text_form(ip_form);
201 return remote; // they get whatever we had as the address.
202}
203
205{
206 return sizeof(port) +
207 + sizeof(int) + ADDRESS_SIZE
208 + sizeof(int) + MAXIMUM_HOSTNAME_LENGTH;
209}
210
211void internet_address::pack(byte_array &packed_form) const
212{
213 attach(packed_form, port);
214 packed_form += byte_array(ADDRESS_SIZE, ip_address);
216}
217
218bool internet_address::unpack(byte_array &packed_form)
219{
220 // check for minimum expected length.
221 if (packed_form.length() < int(sizeof(port)) + ADDRESS_SIZE
223 return false;
224 if (!detach(packed_form, port)) return false;
225 packed_form.stuff(ADDRESS_SIZE, ip_address);
226 packed_form.zap(0, ADDRESS_SIZE - 1);
228 packed_form.zap(0, MAXIMUM_HOSTNAME_LENGTH - 1);
229 return true;
230}
231
232void internet_address::fill(const byte_array &ip, const astring &host,
233 int port_in)
234{
235 port = port_in;
236 int mini = minimum(int(ADDRESS_SIZE), ip.length());
237 for (int i = 0; i < mini; i++) ip_address[i] = ip[i];
238 for (int j = mini; j < ADDRESS_SIZE; j++) ip_address[j] = 0;
239 hostname[0] = '\0';
241}
242
248
250{
251 astring to_print("[");
252 if (astring(hostname).t()) {
253 to_print += "host=";
254 to_print += hostname;
255 to_print += ", ";
256 }
260 to_print += "ip_addr=";
261 for (int i = 0; i < ADDRESS_SIZE; i++) {
262 to_print += a_sprintf("%d", int(ip_address[i]));
263 if (i != ADDRESS_SIZE - 1) to_print += ".";
264 }
265 to_print += ", ";
267 to_print += a_sprintf("port=%u]", port);
268 return to_print;
269}
270
271bool internet_address::is_nil_address(const address_array &ip_address)
272{
273 for (int i = 0; i < ADDRESS_SIZE; i++) if (ip_address[i]) return false;
274 return true;
275}
276
277const abyte nil_address_bytes[] = { 0, 0, 0, 0 };
279 (ADDRESS_SIZE, nil_address_bytes))
280
282{ return is_nil_address(ip_address); }
283
284bool internet_address::same_host(const base_address &compare_in) const
285{
287
288 // they can't be the same if one is a valid address and the other's not, but
289 // they are the same if both addresses are empty.
290 // even so, they're not the same if either's name was non-empty but they're
291 // both nil.
292 if ( (is_nil_address(ip_address) && is_nil_address(to_compare.ip_address))
293 && !astring(hostname) && !astring(to_compare.hostname) )
294 return true;
295 if ( (is_nil_address(ip_address) && is_nil_address(to_compare.ip_address))
296 && (astring(hostname).iequals(to_compare.hostname)) )
297 return true;
298 if (is_nil_address(ip_address)) return false;
299 if (is_nil_address(to_compare.ip_address)) return false;
300
301 // check that the bytes don't differ for the IP address.
302 for (int i = 0; i < ADDRESS_SIZE; i++)
303 if (ip_address[i] != to_compare.ip_address[i])
304 return false; // we have a loser.
305
306 // they could still be different addresses if the hostnames differ...
307
308 if (astring(hostname).t() && astring(to_compare.hostname).t()) {
309 // name comparison.
310 if (astring(hostname).lower() != astring(to_compare.hostname).lower())
311 return false;
312 }
313
314 return true;
315 // all bytes and host were identical, so it's the same address.
316}
317
318bool internet_address::same_port(const base_address &compare_in) const
319{
321 return port == to_compare.port;
322}
323
324bool internet_address::shareable(const base_address &) const
325{ return true; }
326
328{
329#ifdef DEBUG_ADDRESS
330 FUNCDEF("detokenize");
331#endif
333 // either IP address or host must be specified.
334
335 FIND("address", addr);
336#ifdef DEBUG_ADDRESS
337 LOG(astring("info is ") + info + astring('.'));
338 LOG(astring("addr is ") + addr);
339#endif
340 byte_array ip_found;
341 if (addr.t()) {
342 // this bit rips off successive bytes from the string until the internet
343 // address is filled out. ignores any erroneous strings.
344 for (int i = 0; i < ADDRESS_SIZE; i++) {
345#ifdef DEBUG_ADDRESS
346 LOG(astring("ip curr: ") + addr);
347#endif
348 int current_byte = addr.convert(int(0));
349 ip_found += abyte(current_byte);
350#ifdef DEBUG_ADDRESS
351 LOG(a_sprintf("%d: %02x ", i, current_byte));
352#endif
353 int indy = addr.find('.');
354 addr.zap(0, indy); // no error checking, but whatever.
355 }
356 }
357
358 FIND("host", host);
359 GRAB("port", port_t); // this one's definitely needed.
360 int port = port_t.convert(0);
361 fill(ip_found, host, port);
362#ifdef DEBUG_ADDRESS
363 LOG(astring("tcp/ip address found::: ") + text_form());
364#endif
366 return true;
367}
368
370{
371#ifdef DEBUG_ADDRESS
372 FUNCDEF("tokenize");
373#endif
375#ifdef DEBUG_ADDRESS
376 LOG(a_sprintf("host eval is %d for %s", astring(hostname).t(), hostname));
377#endif
378 if (astring(hostname).t()) ADD("host", hostname);
379 bool print_ip = false;
380 for (int i = 0; i < ADDRESS_SIZE; i++) {
381 if (ip_address[i]) print_ip = true;
382 }
383 if (print_ip) {
384 astring ip_addr;
385 for (int i = 0; i < ADDRESS_SIZE; i++)
386 ip_addr += a_sprintf("%d", int(ip_address[i])) + astring(".");
387 ip_addr.zap(ip_addr.end(), ip_addr.end()); // remove last period.
388 ADD("address", ip_addr);
389 }
390 ADD("port", a_sprintf("%d", int(port)));
391#ifdef DEBUG_ADDRESS
392 LOG(astring("your toke's currently ") + fred.text_form());
393#endif
394 DUMP_EXIT;
395}
396
398{
399 for (int i = 0; i < to_check.length(); i++) {
400 char curr = to_check[i];
401 if (curr == '.') continue;
402 if ( (curr >= '0') && (curr <= '9') ) continue;
403 // an unsavory character was seen, so fail out.
404 return false;
405 }
406 return true;
407}
408
409// by Gary Hardley.
410// fixes by CAK 6/26/2002.
411// and more by CAK in november 2010.
413 byte_array &ip_form, bool &all_zeros)
414{
415 astring tmpstr = to_check; // temporary copy of the given address string.
416 all_zeros = true; // default to true until proven otherwise.
417 ip_form.reset(); // empty the address.
418
419 // if it's got anything besides dots and numbers, bail out.
420 if (!appropriate_for_ip(to_check)) return false;
421 // catch a case the below logic does not--where the string starts or
422 // ends with a dot.
423 if ( (to_check[0] == '.') || (to_check[to_check.end()] == '.') )
424 return false;
425 // catch another case that was missed before, where there are multiple dots
426 // in a row but enough numbers to give 4 components.
427 if (to_check.contains("..")) return false;
428
429 // get the first part of the address.
430 char *p = strtok(tmpstr.s(), ".");
431
432 int index = 0;
433 while (p && (index < ADDRESS_SIZE)) {
434 int nTemp = astring(p).convert(-1);
435
436 // is this part of the string a valid number between 0 & 255?
437 if ( (nTemp < 0) || (nTemp > 255) ) return false; // no.
438
439 // yes, assign the number to the next address byte.
440 ip_form += (abyte)nTemp;
441
442 // get the next part of the string
443 p = strtok(NULL_POINTER, ".");
444 }
445
446 // if p is non-null, there was extra stuff at the end, so return false.
447 if (p) return false;
448
449 for (int i = 0; i < ip_form.length(); i++)
450 if (ip_form[i]) { all_zeros = false; break; }
451
452 return ip_form.length() == ADDRESS_SIZE;
453}
454
456{
457 byte_array addr;
458 bool all_zeros;
459 return is_valid_internet_address(to_check, addr, all_zeros);
460}
461
463{
464 return a_sprintf("%d.%d.%d.%d", int(ip_address[0]),
465 int(ip_address[1]), int(ip_address[2]), int(ip_address[3]));
466}
467
468} //namespace.
469
470
#define STORER_ENTRY
#define DUMP_EXIT
#define GRAB(name, value)
#define LOADER_ENTRY
#define ADD(name, value)
#define LOADER_EXIT
#define FIND(name, value)
#define LOG(s)
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition array.h:349
int length() const
Returns the current reported length of the allocated C array.
Definition array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition array.h:769
outcome stuff(int length, contents *to_stuff) const
Copies at most "length" elements from this into the array "to_stuff".
Definition array.h:476
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
astring lower() const
like to_lower(), but returns a new string rather than modifying this.
Definition astring.cpp:545
bool t() const
t() is a shortcut for the string being "true", as in non-empty.
Definition astring.h:97
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition astring.h:113
int convert(int default_value) const
Converts the string into a corresponding integer.
Definition astring.cpp:760
virtual void zap(int start, int end)
Deletes the characters between "start" and "end" inclusively.
Definition astring.cpp:524
bool substring(astring &target, int start, int end) const
a version that stores the substring in an existing "target" string.
Definition astring.cpp:868
virtual void text_form(base_string &state_fill) const
Provides a text view of all the important info owned by this object.
Definition astring.cpp:130
void stuff(char *to_stuff, int count) const
a synonym for copy().
Definition astring.h:216
void reset()
clears out the contents string.
Definition astring.h:202
bool equal_to(const char *that) const
returns true if "that" is equal to this.
Definition astring.cpp:159
int end() const
returns the index of the last (non-null) character in the string.
Definition astring.h:86
int length() const
Returns the current length of the string.
Definition astring.cpp:132
int find(char to_find, int position=0, bool reverse=false) const
Locates "to_find" in "this".
Definition astring.cpp:577
bool contains(const astring &to_find) const
Returns true if "to_find" is contained in this string or false if not.
Definition astring.cpp:162
void to_lower()
to_lower modifies "this" by replacing capitals with lower-case.
Definition astring.cpp:531
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
static bool has_ip_address(const basis::astring &to_check, basis::astring &ip_found)
returns true if "to_check" has an IP address in it somewhere.
basis::astring tokenize() const
static bool valid_address(const basis::astring &to_check)
basis::astring normalize_host() const
basis::astring text_form() const
static const basis::byte_array & nil_address()
static basis::astring ip_address_text_form(const basis::byte_array &ip_address)
void fill(const basis::byte_array &ip_address, const basis::astring &host, int port)
void pack(basis::byte_array &packed_form) const
Creates a packed form of the packable object in "packed_form".
char hostname[MAXIMUM_HOSTNAME_LENGTH]
bool detokenize(const basis::astring &info)
bool unpack(basis::byte_array &packed_form)
Restores the packable from the "packed_form".
bool same_host(const base_address &to_compare) const
static bool ip_appropriate_number(const basis::astring &to_check, int indy, basis::astring &accum)
returns true if "to_check" has a number at "indy" that works in ipv4.
virtual int packed_size() const
Estimates the space needed for the packed structure.
bool shareable(const base_address &to_compare) const
static bool is_valid_internet_address(const basis::astring &to_check, basis::byte_array &ip_form, bool &all_zeros)
static const basis::byte_array & localhost()
static bool appropriate_for_ip(const basis::astring &to_check)
bool same_port(const base_address &to_compare) const
base_address * create_copy() const
static bool is_numeric(char look_at)
returns true if "look_at" is a valid numerical character.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
#define CAST_UP(type)
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
unsigned char abyte
A fairly important unit which is seldom defined...
Definition definitions.h:51
void attach(byte_array &packed_form, const char *to_attach)
Packs a character string "to_attach" into "packed_form".
Definition astring.cpp:1018
bool detach(byte_array &packed_form, astring &to_detach)
Unpacks a character string "to_attach" from "packed_form".
Definition astring.cpp:1026
type minimum(type a, type b)
maximum returns the greater of two values.
Definition functions.h:29
bool negative(const type &a)
negative returns true if "a" is less than zero.
Definition functions.h:43
A logger that sends to the console screen using the standard output device.
Provides access to the operating system's socket methods.
const abyte localhosts_bytes[]
const abyte nil_address_bytes[]
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
#define SAFE_STATIC_CONST(type, func_name, parms)
this version returns a constant object instead.