internet_address.cpp

Go to the documentation of this file.
00001 
00002 // Name   : internet_address
00003 // Author : Chris Koeritz
00005 // Copyright (c) 1995-$now By Author.  This program is free software; you can
00006 // redistribute it and/or modify it under the terms of the GNU General Public
00007 // License as published by the Free Software Foundation:
00008 //     http://www.gnu.org/licenses/gpl.html
00009 // or under the terms of the GNU Library license:
00010 //     http://www.gnu.org/licenses/lgpl.html
00011 // at your preference.  Those licenses describe your legal rights to this
00012 // software, and no other rights or warranties apply.
00013 // Please send updates for this code to: fred@gruntose.com -- Thanks, fred.
00015 
00016 #include "internet_address.h"
00017 #include "machine_uid.h"
00018 
00019 #include <basis/byte_array.h>
00020 #include <basis/functions.h>
00021 #include <basis/astring.h>
00022 #include <basis/mutex.h>
00023 #include <configuration/configurator.h>
00024 #include <configuration/variable_tokenizer.h>
00025 #include <loggers/program_wide_logger.h>
00026 #include <structures/static_memory_gremlin.h>
00027 #include <structures/string_table.h>
00028 #include <textual/parser_bits.h>
00029 
00030 #include <stdio.h>
00031 #include <string.h>
00032 
00033 using namespace basis;
00034 using namespace configuration;
00035 using namespace loggers;
00036 using namespace structures;
00037 using namespace textual;
00038 
00039 namespace sockets {
00040 
00041 //#define DEBUG_ADDRESS
00042   // uncomment if you want a debugging version of address.
00043 
00045 
00046 #undef LOG
00047 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
00048 
00050 
00051 /*
00052 //hmmm: consider moving the functions for storage out to a helper file.
00053 
00054 internet_address internet_address::load(configurator &config,
00055     const astring &section, const astring &name, const internet_address &def)
00056 {
00057   astring token_list;
00058   if (!config.get(section, name, token_list)) {
00059     // no entry stored means no address.  set the address to the default.
00060     config.put(section, name, def.tokenize());
00061     return def;
00062   }
00063   internet_address to_return;
00064   // get the rest of the work done by detokenize.
00065   if (to_return.detokenize(token_list)) return to_return;
00066   // didn't work, dang it.  Note that we don't reject it here and store the
00067   // default.  that's because this indicates an error in formatting of the 
00068   // address, and we want the user to have a chance to correct that and try
00069   // again.
00070   return internet_address();
00071 }
00072 
00073 bool internet_address::store(configurator &config, const astring &section,
00074     const astring &name, const internet_address &to_store)
00075 {
00076   astring text = to_store.tokenize();
00077   return config.put(section, name, text);
00078 }
00079 */
00080 
00082 
00083 // provides an easy way to cast to the proper type and provide a non-pointer
00084 // to work with.
00085 #define CAST_UP(type) \
00086   const type *temp = dynamic_cast<const type *>(&compare_in); \
00087   if (!temp) return false;  /* shouldn't happen but it means bad things. */ \
00088   const type &to_compare = *temp;
00089 
00091 
00092 internet_address::internet_address() { fill(byte_array(), "", 0); }
00093 
00094 internet_address::internet_address(const byte_array &ip,
00095     const astring &host, int port_in)
00096 { fill(ip, host, port_in); }
00097 
00098 //hmmm: for ipv6, we will need a new object, called ipv6_address perhaps.
00099 //      it will copy everything here but will have a longer address array.
00100 //      we will need a new object for ipv6_machine_uid also.
00101 
00102 machine_uid internet_address::convert() const
00103 { return internet_machine_uid(hostname, byte_array(ADDRESS_SIZE, ip_address)); }
00104 
00105 bool internet_address::ip_appropriate_number(const astring &to_check, int indy,
00106     astring &accum)
00107 {
00108 //  FUNCDEF("ip_appropriate_number");
00109   accum.reset();
00110   for (int i = indy; (i < indy + 3) && (i < to_check.length()); i++) {
00111     // make sure it looks like a good number.
00112     if (!parser_bits::is_numeric(to_check[i]) || (to_check[i] == '-') ) {
00113       // this one doesn't look good right here, but if we already got a digit,
00114       // we're okay.
00115       if (i == indy) return false;  // hadn't gotten any digits at all yet.
00116       else break;  // got one, so let's check our progress below.
00117     }
00118     accum += to_check[i];  // snag the current digit.
00119   }
00120   if (!accum.length()) return false;  // how would that happen?
00121   int convert = accum.convert(-1);
00122   return (convert >= 0) && (convert <= 255);
00123 }
00124 
00125 // needs to see 1-3 numbers, period, 1-3 numbers, period etc...
00126 // for a total of three periods and 4 number sets.
00127 bool internet_address::has_ip_address(const astring &to_check,
00128     astring &ip_found)
00129 {
00130 //  FUNCDEF("has_ip_address");
00131   int nums_seen = 0;
00132   ip_found.reset();
00133   for (int i = 0; i < to_check.length(); i++) {
00134     bool hosed = false;
00135     astring num_found;
00136 //    if (!!ip_found) LOG(astring("current ip found=") + ip_found);
00137     if (!ip_appropriate_number(to_check, i, num_found)) {
00138 //      LOG(a_sprintf("no ip approp %d", i));
00139       hosed = true;
00140     } else {
00141       // we're seeing the number we want here.
00142 //      LOG(astring("num found = ") + num_found);
00143       nums_seen++;
00144       if (nums_seen >= 4) {
00145         ip_found += num_found;  // get our last part.
00146         return true;  // hey, that's a match.
00147       }
00148       // look for a period now.
00149       int period_indy = to_check.find('.', i);
00150       if (negative(period_indy) || (period_indy > i + 3) ) hosed = true;
00151       else {
00152         for (int x = i; x < period_indy; x++) {
00153           if (!parser_bits::is_numeric(to_check[x]) || (to_check[x] == '-')) {
00154 //            LOG(a_sprintf("hosed by bad char at %d -> %c", x, to_check[x]));
00155             hosed = true;  // wrong character seen in between.
00156           }
00157         }
00158         if (!hosed) {
00159           ip_found += to_check.substring(i, period_indy);
00160           i = period_indy;  // skip to where our next number should be.
00161         }
00162       }
00163     }
00164     if (hosed) {
00165       nums_seen = 0;
00166       ip_found.reset();
00167     }
00168   }
00169   return false;
00170 }
00171 
00172 const abyte localhosts_bytes[] = { 127, 0, 0, 1 };
00173 SAFE_STATIC_CONST(byte_array, internet_address::localhost,
00174     (ADDRESS_SIZE, localhosts_bytes))
00175 
00176 bool internet_address::is_localhost() const
00177 {
00178   // check whether the host is "local" or "localhost".
00179   astring host = hostname;
00180   host.to_lower();
00181   if ( (host.equal_to("local")) || (host.equal_to("localhost")) )
00182     return true;
00183 
00184   // check whether the address is local even if the hostname wasn't.
00185   for (int i = 0; i < ADDRESS_SIZE; i++) {
00186     if (ip_address[i] != localhost().get(i))
00187       return false;
00188   }
00189 
00190   return true;  // the address matched.
00191 }
00192 
00193 astring internet_address::normalize_host() const
00194 {
00195   // try the hostname first.
00196   astring remote = hostname;
00197   if (remote.t()) return remote;
00198   // there was no host we can use; try the IP address instead.
00199   byte_array ip_form(ADDRESS_SIZE, ip_address);
00200   remote = ip_address_text_form(ip_form);
00201   return remote;  // they get whatever we had as the address.
00202 }
00203 
00204 int internet_address::packed_size() const
00205 {
00206   return sizeof(port) +
00207       + sizeof(int) + ADDRESS_SIZE
00208       + sizeof(int) + MAXIMUM_HOSTNAME_LENGTH;
00209 }
00210 
00211 void internet_address::pack(byte_array &packed_form) const
00212 {
00213   attach(packed_form, port);
00214   packed_form += byte_array(ADDRESS_SIZE, ip_address);
00215   packed_form += byte_array(MAXIMUM_HOSTNAME_LENGTH, (abyte *)hostname);
00216 }
00217 
00218 bool internet_address::unpack(byte_array &packed_form)
00219 {
00220   // check for minimum expected length.
00221   if (packed_form.length() < int(sizeof(port)) + ADDRESS_SIZE
00222       + MAXIMUM_HOSTNAME_LENGTH)
00223     return false;
00224   if (!detach(packed_form, port)) return false;
00225   packed_form.stuff(ADDRESS_SIZE, ip_address);
00226   packed_form.zap(0, ADDRESS_SIZE - 1);
00227   packed_form.stuff(MAXIMUM_HOSTNAME_LENGTH, (abyte *)hostname);
00228   packed_form.zap(0, MAXIMUM_HOSTNAME_LENGTH - 1);
00229   return true;
00230 }
00231 
00232 void internet_address::fill(const byte_array &ip, const astring &host,
00233     int port_in)
00234 {
00235   port = port_in;
00236   int mini = minimum(int(ADDRESS_SIZE), ip.length());
00237   for (int i = 0; i < mini; i++) ip_address[i] = ip[i];
00238   for (int j = mini; j < ADDRESS_SIZE; j++) ip_address[j] = 0;
00239   hostname[0] = '\0';
00240   host.stuff(hostname, MAXIMUM_HOSTNAME_LENGTH - 1);
00241 }
00242 
00243 base_address *internet_address::create_copy() const
00244 {
00245   return new internet_address(byte_array(ADDRESS_SIZE, ip_address),
00246       hostname, port);
00247 }
00248 
00249 astring internet_address::text_form() const
00250 {
00251   astring to_print("[");
00252   if (astring(hostname).t()) {
00253     to_print += "host=";
00254     to_print += hostname;
00255     to_print += ", ";
00256   }
00260     to_print += "ip_addr=";
00261     for (int i = 0; i < ADDRESS_SIZE; i++) {
00262       to_print += a_sprintf("%d", int(ip_address[i]));
00263       if (i != ADDRESS_SIZE - 1) to_print += ".";
00264     }
00265     to_print += ", ";
00267   to_print += a_sprintf("port=%u]", port);
00268   return to_print;
00269 }
00270 
00271 bool internet_address::is_nil_address(const address_array &ip_address)
00272 {
00273   for (int i = 0; i < ADDRESS_SIZE; i++) if (ip_address[i]) return false;
00274   return true;
00275 }
00276 
00277 const abyte nil_address_bytes[] = { 0, 0, 0, 0 };
00278 SAFE_STATIC_CONST(byte_array, internet_address::nil_address,
00279     (ADDRESS_SIZE, nil_address_bytes))
00280 
00281 bool internet_address::is_nil_address() const
00282 { return is_nil_address(ip_address); }
00283 
00284 bool internet_address::same_host(const base_address &compare_in) const
00285 {
00286   CAST_UP(internet_address);
00287 
00288   // they can't be the same if one is a valid address and the other's not, but
00289   // they are the same if both addresses are empty.
00290   // even so, they're not the same if either's name was non-empty but they're
00291   // both nil.
00292   if ( (is_nil_address(ip_address) && is_nil_address(to_compare.ip_address))
00293       && !astring(hostname) && !astring(to_compare.hostname) )
00294     return true;
00295   if ( (is_nil_address(ip_address) && is_nil_address(to_compare.ip_address))
00296       && (astring(hostname).iequals(to_compare.hostname)) )
00297     return true;
00298   if (is_nil_address(ip_address)) return false;
00299   if (is_nil_address(to_compare.ip_address)) return false;
00300 
00301   // check that the bytes don't differ for the IP address.
00302   for (int i = 0; i < ADDRESS_SIZE; i++)
00303     if (ip_address[i] != to_compare.ip_address[i])
00304       return false;  // we have a loser.
00305 
00306   // they could still be different addresses if the hostnames differ...
00307 
00308   if (astring(hostname).t() && astring(to_compare.hostname).t()) {
00309     // name comparison.
00310     if (astring(hostname).lower() != astring(to_compare.hostname).lower())
00311       return false;
00312   }
00313 
00314   return true;
00315     // all bytes and host were identical, so it's the same address.
00316 }
00317 
00318 bool internet_address::same_port(const base_address &compare_in) const
00319 {
00320   CAST_UP(internet_address);
00321   return port == to_compare.port;
00322 }
00323 
00324 bool internet_address::shareable(const base_address &) const
00325 { return true; }
00326 
00327 bool internet_address::detokenize(const astring &info)
00328 {
00329 #ifdef DEBUG_ADDRESS
00330   FUNCDEF("detokenize");
00331 #endif
00332   LOADER_ENTRY;
00333   // either IP address or host must be specified.
00334 
00335   FIND("address", addr);
00336 #ifdef DEBUG_ADDRESS
00337   LOG(astring("info is ") + info + astring('.'));
00338   LOG(astring("addr is ") + addr);
00339 #endif
00340   byte_array ip_found;
00341   if (addr.t()) {
00342     // this bit rips off successive bytes from the string until the internet
00343     // address is filled out.  ignores any erroneous strings.
00344     for (int i = 0; i < ADDRESS_SIZE; i++) {
00345 #ifdef DEBUG_ADDRESS
00346       LOG(astring("ip curr: ") + addr);
00347 #endif
00348       int current_byte = addr.convert(int(0));
00349       ip_found += abyte(current_byte);
00350 #ifdef DEBUG_ADDRESS
00351       LOG(a_sprintf("%d: %02x ", i, current_byte));
00352 #endif
00353       int indy = addr.find('.');
00354       addr.zap(0, indy);  // no error checking, but whatever.
00355     }
00356   }
00357 
00358   FIND("host", host);
00359   GRAB("port", port_t);  // this one's definitely needed.
00360   int port = port_t.convert(0);
00361   fill(ip_found, host, port);
00362 #ifdef DEBUG_ADDRESS
00363   LOG(astring("tcp/ip address found::: ") + text_form());
00364 #endif
00365   LOADER_EXIT;
00366   return true;
00367 }
00368 
00369 astring internet_address::tokenize() const
00370 {
00371 #ifdef DEBUG_ADDRESS
00372   FUNCDEF("tokenize");
00373 #endif
00374   STORER_ENTRY;
00375 #ifdef DEBUG_ADDRESS
00376   LOG(a_sprintf("host eval is %d for %s", astring(hostname).t(), hostname));
00377 #endif
00378   if (astring(hostname).t()) ADD("host", hostname);
00379   bool print_ip = false;
00380   for (int i = 0; i < ADDRESS_SIZE; i++) {
00381     if (ip_address[i]) print_ip = true;
00382   }
00383   if (print_ip) {
00384     astring ip_addr;
00385     for (int i = 0; i < ADDRESS_SIZE; i++)
00386       ip_addr += a_sprintf("%d", int(ip_address[i])) + astring(".");
00387     ip_addr.zap(ip_addr.end(), ip_addr.end());  // remove last period. 
00388     ADD("address", ip_addr);
00389   }
00390   ADD("port", a_sprintf("%d", int(port)));
00391 #ifdef DEBUG_ADDRESS
00392   LOG(astring("your toke's currently ") + fred.text_form());
00393 #endif
00394   DUMP_EXIT;
00395 }
00396 
00397 bool internet_address::appropriate_for_ip(const astring &to_check)
00398 {
00399   for (int i = 0; i < to_check.length(); i++) {
00400     char curr = to_check[i];
00401     if (curr == '.') continue;
00402     if ( (curr >= '0') && (curr <= '9') ) continue;
00403     // an unsavory character was seen, so fail out.
00404     return false;
00405   }
00406   return true;
00407 }
00408 
00409 // by Gary Hardley.
00410 // fixes by CAK 6/26/2002.
00411 // and more by CAK in november 2010.
00412 bool internet_address::is_valid_internet_address(const astring &to_check,
00413     byte_array &ip_form, bool &all_zeros)
00414 {
00415   astring tmpstr = to_check;  // temporary copy of the given address string.
00416   all_zeros = true;  // default to true until proven otherwise.
00417   ip_form.reset();  // empty the address.
00418 
00419   // if it's got anything besides dots and numbers, bail out.
00420   if (!appropriate_for_ip(to_check)) return false;
00421   // catch a case the below logic does not--where the string starts or
00422   // ends with a dot.
00423   if ( (to_check[0] == '.') || (to_check[to_check.end()] == '.') )
00424     return false;
00425   // catch another case that was missed before, where there are multiple dots
00426   // in a row but enough numbers to give 4 components.
00427   if (to_check.contains("..")) return false;
00428 
00429   // get the first part of the address.
00430   char *p = strtok(tmpstr.s(), ".");
00431 
00432   int index = 0;
00433   while (p && (index < ADDRESS_SIZE)) {
00434     int nTemp = astring(p).convert(-1);
00435 
00436     // is this part of the string a valid number between 0 & 255?
00437     if ( (nTemp < 0) || (nTemp > 255) ) return false;  // no.
00438 
00439     // yes, assign the number to the next address byte.
00440     ip_form += (abyte)nTemp;
00441 
00442     // get the next part of the string
00443     p = strtok(NIL, ".");
00444   }
00445 
00446   // if p is non-null, there was extra stuff at the end, so return false.
00447   if (p) return false;
00448 
00449   for (int i = 0; i < ip_form.length(); i++)
00450     if (ip_form[i]) { all_zeros = false; break; }
00451 
00452   return ip_form.length() == ADDRESS_SIZE;
00453 }
00454 
00455 bool internet_address::valid_address(const astring &to_check)
00456 {
00457   byte_array addr;
00458   bool all_zeros;
00459   return is_valid_internet_address(to_check, addr, all_zeros);
00460 }
00461 
00462 astring internet_address::ip_address_text_form(const byte_array &ip_address)
00463 {
00464   return a_sprintf("%d.%d.%d.%d", int(ip_address[0]),
00465       int(ip_address[1]), int(ip_address[2]), int(ip_address[3]));
00466 }
00467 
00468 } //namespace.
00469 
00470 
Generated on Sat Jan 28 04:22:43 2012 for hoople2 project by  doxygen 1.6.3