address.cpp

Go to the documentation of this file.
00001 #ifndef ADDRESS_IMPLEMENTATION_FILE
00002 #define ADDRESS_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : network_address                                                   *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 1995-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 #include "address.h"
00019 #include "imp_sockets.h"
00020 #include "machine_uid.h"
00021 
00022 #include <basis/byte_array.h>
00023 #include <basis/function.h>
00024 #include <basis/istring.h>
00025 #include <basis/mutex.h>
00026 #include <data_struct/configurator.h>
00027 #include <data_struct/static_memory_gremlin.h>
00028 #include <data_struct/string_table.h>
00029 #include <textual/parser_bits.h>
00030 #include <textual/tokenizer.h>
00031 
00032 #include <stdio.h>
00033 #include <string.h>
00034 
00035 using namespace basis;
00036 
00037 //#define DEBUG_ADDRESS
00038   // uncomment if you want a debugging version of address.
00039 
00041 
00042 #undef LOG
00043 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger(), to_print)
00044 
00046 
00047 network_address::network_address()
00048 : _type(UNINITIALIZED_ADDRESS),
00049   _addr(NIL)
00050 {}
00051 
00052 network_address::network_address(const network_address &to_copy)
00053 : packable(),
00054   _type(to_copy._type),
00055   _addr(to_copy._addr? to_copy._addr->create_copy() : NIL)
00056 {}
00057 
00058 network_address::network_address(const internet_address &address)
00059 : _type(INTERNET_ADDRESS),
00060   _addr(address.create_copy())
00061 {}
00062 
00063 #ifndef EMBEDDED_BUILD
00064 
00065 network_address::network_address(const serial_port_address &address)
00066 : _type(SERIAL_PORT_ADDRESS),
00067   _addr(address.create_copy())
00068 {}
00069 
00070 network_address::network_address(const ipc_address &address)
00071 : _type(IPC_ADDRESS),
00072   _addr(address.create_copy())
00073 {}
00074 
00075 #endif
00076 
00077 network_address::~network_address()
00078 {
00079   _type = UNINITIALIZED_ADDRESS;
00080   WHACK(_addr);
00081 }
00082 
00083 network_address &network_address::operator =(const network_address &to_copy)
00084 {
00085   if (this == &to_copy) return *this;
00086   WHACK(_addr);
00087   _type = to_copy._type;
00088   if (to_copy._addr)
00089     _addr = to_copy._addr->create_copy();
00090   return *this;
00091 }
00092 
00093 bool network_address::valid() const
00094 { return (_type > ADDRESS_SENTINEL_BEGIN) && (_type < ADDRESS_SENTINEL_END); }
00095 
00096 internet_address *network_address::internet()
00097 { return dynamic_cast<internet_address *>(_addr); }
00098 
00099 #ifndef EMBEDDED_BUILD
00100 serial_port_address *network_address::serial()
00101 { return dynamic_cast<serial_port_address *>(_addr); }
00102 
00103 ipc_address *network_address::ipc()
00104 { return dynamic_cast<ipc_address *>(_addr); }
00105 #endif
00106 
00107 const internet_address *network_address::internet() const
00108 { return dynamic_cast<const internet_address *>(_addr); }
00109 
00110 #ifndef EMBEDDED_BUILD
00111 const serial_port_address *network_address::serial() const
00112 { return dynamic_cast<const serial_port_address *>(_addr); }
00113 
00114 const ipc_address *network_address::ipc() const
00115 { return dynamic_cast<const ipc_address *>(_addr); }
00116 #endif
00117 
00118 bool network_address::comparable(address_type a, address_type b) const
00119 {
00120   return (a == b);
00121 /*    || ( (a == MODEM_ADDRESS) && (b == SERIAL_PORT_ADDRESS) )
00122       || ( (b == MODEM_ADDRESS) && (a == SERIAL_PORT_ADDRESS) ); */
00123 }
00124 
00125 int network_address::packed_size() const
00126 {
00127   if (!_addr) return 0;  // bogus.
00128   return _addr->packed_size();
00129 }
00130 
00131 bool network_address::same_host(const network_address &to_compare) const
00132 {
00133   FUNCDEF("same_host");
00134   if (!comparable(address_type(_type), address_type(to_compare._type)))
00135     return false;
00136   if (!_addr) return true;  // uninitialized.
00137   return _addr->same_host(*to_compare._addr);
00138 }
00139 
00140 bool network_address::same_port(const network_address &to_compare) const
00141 {
00142   FUNCDEF("same_port");
00143   if (!comparable(address_type(_type), address_type(to_compare._type)))
00144     return false;
00145   if (!_addr) return true;  // uninitialized.
00146   return _addr->same_port(*to_compare._addr);
00147 }
00148 
00149 bool network_address::shareable(const network_address &to_compare) const
00150 {
00151   if (! operator == (to_compare)) return false;
00152     // if the addresses are not basically identical, then they're not shareable.
00153 
00154   if (!_addr) return false;  // uninitialized.
00155   return _addr->shareable(*to_compare._addr);
00156 }
00157 
00158 bool network_address::operator == (const network_address &to_compare) const
00159 { return same_host(to_compare) && same_port(to_compare); }
00160 
00161 istring network_address::text_for_type(address_type type) 
00162 {
00163   istring to_return;
00164   switch (type) {
00165     case UNINITIALIZED_ADDRESS: return "Uninitialized";
00166     case IPC_ADDRESS: return "IPC";
00167     case INTERNET_ADDRESS: return "TCP/IP";
00168     case SERIAL_PORT_ADDRESS: return "Serial_Port";
00169     default:
00170       return isprintf("unknown address type %d", type);
00171   }
00172 }
00173 
00174 #define APPROX(t) (t.lower()).substring(0, 2)
00175 
00176 network_address::address_type network_address::type_from_text
00177   (const istring &text)
00178 {
00179   if (APPROX(text) == APPROX(text_for_type(IPC_ADDRESS)))
00180     return IPC_ADDRESS;
00181   if (APPROX(text) == APPROX(text_for_type(INTERNET_ADDRESS)))
00182     return INTERNET_ADDRESS;
00183   if (APPROX(text) == APPROX(text_for_type(SERIAL_PORT_ADDRESS)))
00184     return SERIAL_PORT_ADDRESS;
00185   return UNINITIALIZED_ADDRESS;
00186 }
00187 
00188 istring network_address::text_form(bool show_type) const
00189 {
00190   istring to_return;
00191   if (show_type) {
00192     istring type_to_print(text_for_type(type()));
00193     if (_addr) type_to_print += " ";
00194       // only add a space if we expect to have some contents.
00195     to_return += type_to_print;
00196   }
00197   if (_addr) to_return += _addr->text_form();
00198   return to_return;
00199 }
00200 
00201 istring network_address::unified_hostname() const
00202 {
00203   istring to_return;
00204   if (type() == network_address::INTERNET_ADDRESS) {
00205     to_return = internet()->normalize_host();
00206   } else if (type() == network_address::IPC_ADDRESS) {
00207     to_return = "local";
00208   } else {
00209     to_return = "n/a";
00210   }
00211   return to_return;
00212 }
00213 
00214 istring network_address::tokenize() const
00215 {
00216   istring to_return("type");
00217   to_return += TOKEN_ASSIGN();
00218   to_return += text_for_type(type());
00219   // add a separator if there is any tokenized data.
00220   if (_addr) {
00221     to_return += TOKEN_SEPARATOR();
00222     to_return += ' ';
00223     to_return += _addr->tokenize();
00224   }
00225   return to_return;
00226 }
00227 
00228 // fills in an address of the "addr_type" from the token list.
00229 #define FILL(addr_type) { \
00230   addr_type *low = new addr_type; \
00231   worked = low->detokenize(info); \
00232   if (worked) _addr = low; \
00233   else WHACK(low); \
00234   break; \
00235 }
00236 
00237 bool network_address::detokenize(const istring &info)
00238 {
00239   FUNCDEF("detokenize");
00240   // clear out existing stuff first.
00241   _type = UNINITIALIZED_ADDRESS;
00242   WHACK(_addr);
00243 
00244   int first_sep = info.find(TOKEN_SEPARATOR());
00245   if (negative(first_sep))
00246     first_sep = info.length();
00247 
00248   int first_assign = info.find(TOKEN_ASSIGN());
00249   if (negative(first_assign)) return false;  // no separator means it's bogus.
00250 
00251   // the positions of the "type" string and it's value have now been computed.
00252   // let's hope it's there.
00253   istring type_tag = info.substring(0, first_assign - 1);
00254   type_tag.strip_spaces();
00255   if (type_tag.lower() != istring("type")) return false;
00256     // wrong tag found first.
00257 
00258   istring type_name = info.substring(first_assign + 1, first_sep - 1);
00259   type_name.strip_spaces();
00260 
00261   bool worked = false;
00262 
00263   _type = type_from_text(type_name);
00264   switch (_type) {
00265     case UNINITIALIZED_ADDRESS: worked = true; break; 
00266     case INTERNET_ADDRESS: FILL(internet_address);
00267 #ifndef EMBEDDED_BUILD
00268     case SERIAL_PORT_ADDRESS: FILL(serial_port_address);
00269     case IPC_ADDRESS: FILL(ipc_address);
00270 #endif
00271     default: {
00272       LOG(isprintf("unknown type %d.", _type));
00273       break;
00274     }
00275   }
00276   return worked;
00277 }
00278 
00279 //hmmm: consider moving the functions for storage out to a helper file.
00280 
00281 network_address network_address::load(configurator &config,
00282     const istring &section, const istring &name, const network_address &def)
00283 {
00284   istring token_list;
00285   if (!config.get(section, name, token_list)) {
00286     // no entry stored means no address.  set the address to the default.
00287     config.put(section, name, def.tokenize());
00288     return def;
00289   }
00290   network_address to_return;
00291   // get the rest of the work done by detokenize.
00292   if (to_return.detokenize(token_list)) return to_return;
00293   // didn't work, dang it.  Note that we don't reject it here and store the
00294   // default.  that's because this indicates an error in formatting of the 
00295   // address, and we want the user to have a chance to correct that and try
00296   // again.
00297   return network_address();
00298 }
00299 
00300 bool network_address::store(configurator &config, const istring &section,
00301     const istring &name, const network_address &to_store)
00302 {
00303   istring text = to_store.tokenize();
00304   return config.put(section, name, text);
00305 }
00306 
00307 void network_address::parse_pack(byte_array &packed_form) const
00308 { tokenize().pack(packed_form); }
00309 
00310 bool network_address::parse_unpack(byte_array &packed_form)
00311 {
00312   istring tokenized;
00313   if (!tokenized.unpack(packed_form)) return false;
00314   if (!detokenize(tokenized)) return false;
00315   return true;
00316 }
00317 
00318 machine_uid network_address::convert() const
00319 {
00320   if (!_addr) return machine_uid();
00321   return _addr->convert(); 
00322 }
00323 
00324 void network_address::pack(byte_array &packed_form) const
00325 {
00326   attach(packed_form, int(_type));
00327   if (_addr) _addr->pack(packed_form);
00328 }
00329 
00330 bool network_address::unpack(byte_array &packed_form)
00331 {
00332   FUNCDEF("unpack");
00333   // trash current stuff.
00334   WHACK(_addr);
00335   _type = UNINITIALIZED_ADDRESS;
00336   int type;
00337   if (!detach(packed_form, type)) return false;
00338   _type = type;
00339   switch (_type) {
00340     case UNINITIALIZED_ADDRESS: return true;
00341     case INTERNET_ADDRESS: _addr = new internet_address(); break;
00342 #ifndef EMBEDDED_BUILD
00343     case SERIAL_PORT_ADDRESS: _addr = new serial_port_address(); break;
00344     case IPC_ADDRESS: _addr = new ipc_address(); break;
00345 #endif
00346     default: {
00347       LOG(isprintf("unknown type %d.", _type));
00348       return false;
00349     }
00350   }
00351   bool to_return = _addr->unpack(packed_form);
00352   if (!to_return) {
00353     _type = UNINITIALIZED_ADDRESS;
00354     WHACK(_addr);
00355   }
00356   return to_return;
00357 }
00358 
00360 
00361 // provides an easy way to cast to the proper type and provide a non-pointer
00362 // to work with.
00363 #define CAST_UP(type) \
00364   const type *temp = dynamic_cast<const type *>(&compare_in); \
00365   if (!temp) return false;  /* shouldn't happen but it means bad things. */ \
00366   const type &to_compare = *temp;
00367 
00369 
00370 internet_address::internet_address() { fill(byte_array(), "", 0); }
00371 
00372 internet_address::internet_address(const byte_array &ip,
00373     const istring &host, int port_in)
00374 { fill(ip, host, port_in); }
00375 
00376 //hmmm: for ipv6, we will need a new object, called ipv6_address perhaps.
00377 //      it will copy everything here but will have a longer address array.
00378 //      we will need a new object for ipv6_machine_uid also.
00379 
00380 machine_uid internet_address::convert() const
00381 { return internet_machine_uid(hostname, byte_array(ADDRESS_SIZE, ip_address)); }
00382 
00383 bool internet_address::ip_appropriate_number(const istring &to_check, int indy,
00384     istring &accum)
00385 {
00386   FUNCDEF("ip_appropriate_number");
00387   accum.reset();
00388   for (int i = indy; (i < indy + 3) && (i < to_check.length()); i++) {
00389     // make sure it looks like a good number.
00390     if (!parser_bits::is_numeric(to_check[i]) || (to_check[i] == '-') ) {
00391       // this one doesn't look good right here, but if we already got a digit,
00392       // we're okay.
00393       if (i == indy) return false;  // hadn't gotten any digits at all yet.
00394       else break;  // got one, so let's check our progress below.
00395     }
00396     accum += to_check[i];  // snag the current digit.
00397   }
00398   if (!accum.length()) return false;  // how would that happen?
00399   int convert = accum.convert(-1);
00400   return (convert >= 0) && (convert <= 255);
00401 }
00402 
00403 // needs to see 1-3 numbers, period, 1-3 numbers, period etc...
00404 // for a total of three periods and 4 number sets.
00405 bool internet_address::has_ip_address(const istring &to_check,
00406     istring &ip_found)
00407 {
00408   FUNCDEF("has_ip_address");
00409   int nums_seen = 0;
00410   ip_found.reset();
00411   for (int i = 0; i < to_check.length(); i++) {
00412     bool hosed = false;
00413     istring num_found;
00414 //    if (!!ip_found) LOG(istring("current ip found=") + ip_found);
00415     if (!ip_appropriate_number(to_check, i, num_found)) {
00416 //      LOG(isprintf("no ip approp %d", i));
00417       hosed = true;
00418     } else {
00419       // we're seeing the number we want here.
00420 //      LOG(istring("num found = ") + num_found);
00421       nums_seen++;
00422       if (nums_seen >= 4) {
00423         ip_found += num_found;  // get our last part.
00424         return true;  // hey, that's a match.
00425       }
00426       // look for a period now.
00427       int period_indy = to_check.find('.', i);
00428       if (negative(period_indy) || (period_indy > i + 3) ) hosed = true;
00429       else {
00430         for (int x = i; x < period_indy; x++) {
00431           if (!parser_bits::is_numeric(to_check[x]) || (to_check[x] == '-')) {
00432 //            LOG(isprintf("hosed by bad char at %d -> %c", x, to_check[x]));
00433             hosed = true;  // wrong character seen in between.
00434           }
00435         }
00436         if (!hosed) {
00437           ip_found += to_check.substring(i, period_indy);
00438           i = period_indy;  // skip to where our next number should be.
00439         }
00440       }
00441     }
00442     if (hosed) {
00443       nums_seen = 0;
00444       ip_found.reset();
00445     }
00446   }
00447   return false;
00448 }
00449 
00450 const byte localhosts_bytes[] = { 127, 0, 0, 1 };
00451 SAFE_STATIC_CONST(byte_array, internet_address::localhost,
00452     (ADDRESS_SIZE, localhosts_bytes))
00453 
00454 bool internet_address::is_localhost() const
00455 {
00456   // check whether the host is "local" or "localhost".
00457   istring host = hostname;
00458   host.to_lower();
00459   if ( (host == "local") || (host == "localhost") )
00460     return true;
00461 
00462   // check whether the address is local even if the hostname wasn't.
00463   for (int i = 0; i < ADDRESS_SIZE; i++) {
00464     if (ip_address[i] != localhost().get(i))
00465       return false;
00466   }
00467 
00468   return true;  // the address matched.
00469 }
00470 
00471 istring internet_address::normalize_host() const
00472 {
00473   // try the hostname first.
00474   istring remote = hostname;
00475   if (remote.t()) return remote;
00476   // there was no host we can use; try the IP address instead.
00477   byte_array ip_form(ADDRESS_SIZE, ip_address);
00478   remote = ip_address_text_form(ip_form);
00479   return remote;  // they get whatever we had as the address.
00480 }
00481 
00482 int internet_address::packed_size() const
00483 {
00484   return sizeof(port) +
00485       + sizeof(int) + ADDRESS_SIZE
00486       + sizeof(int) + MAXIMUM_HOSTNAME_LENGTH;
00487 }
00488 
00489 void internet_address::pack(byte_array &packed_form) const
00490 {
00491   attach(packed_form, port);
00492   packed_form += byte_array(ADDRESS_SIZE, ip_address);
00493   packed_form += byte_array(MAXIMUM_HOSTNAME_LENGTH, (byte *)hostname);
00494 }
00495 
00496 bool internet_address::unpack(byte_array &packed_form)
00497 {
00498   // check for minimum expected length.
00499   if (packed_form.length() < int(sizeof(port)) + ADDRESS_SIZE
00500       + MAXIMUM_HOSTNAME_LENGTH)
00501     return false;
00502   if (!detach(packed_form, port)) return false;
00503   packed_form.stuff(ADDRESS_SIZE, ip_address);
00504   packed_form.zap(0, ADDRESS_SIZE - 1);
00505   packed_form.stuff(MAXIMUM_HOSTNAME_LENGTH, (byte *)hostname);
00506   packed_form.zap(0, MAXIMUM_HOSTNAME_LENGTH - 1);
00507   return true;
00508 }
00509 
00510 void internet_address::fill(const byte_array &ip, const istring &host,
00511     int port_in)
00512 {
00513   port = port_in;
00514   int mini = minimum(int(ADDRESS_SIZE), ip.length());
00515   for (int i = 0; i < mini; i++) ip_address[i] = ip[i];
00516   for (int j = mini; j < ADDRESS_SIZE; j++) ip_address[j] = 0;
00517   hostname[0] = '\0';
00518   host.stuff(hostname, MAXIMUM_HOSTNAME_LENGTH - 1);
00519 }
00520 
00521 address_base *internet_address::create_copy() const
00522 {
00523   return new internet_address(byte_array(ADDRESS_SIZE, ip_address),
00524       hostname, port);
00525 }
00526 
00527 istring internet_address::text_form() const
00528 {
00529   istring to_print("[");
00530   if (istring(hostname).t()) {
00531     to_print += "host=";
00532     to_print += hostname;
00533     to_print += ", ";
00534   }
00538     to_print += "ip_addr=";
00539     for (int i = 0; i < ADDRESS_SIZE; i++) {
00540       to_print += isprintf("%d", int(ip_address[i]));
00541       if (i != ADDRESS_SIZE - 1) to_print += ".";
00542     }
00543     to_print += ", ";
00545   to_print += isprintf("port=%u]", port);
00546   return to_print;
00547 }
00548 
00549 bool internet_address::is_nil_address(const address_array &ip_address)
00550 {
00551   for (int i = 0; i < ADDRESS_SIZE; i++) if (ip_address[i]) return false;
00552   return true;
00553 }
00554 
00555 const byte nil_address_bytes[] = { 0, 0, 0, 0 };
00556 SAFE_STATIC_CONST(byte_array, internet_address::nil_address,
00557     (ADDRESS_SIZE, nil_address_bytes))
00558 
00559 bool internet_address::is_nil_address() const
00560 { return is_nil_address(ip_address); }
00561 
00562 bool internet_address::same_host(const address_base &compare_in) const
00563 {
00564   CAST_UP(internet_address);
00565 
00566   // they can't be the same if one is a valid address and the other's not, but
00567   // they are the same if both addresses are empty.
00568   // even so, they're not the same if either's name was non-empty but they're
00569   // both nil.
00570   if ( (is_nil_address(ip_address) && is_nil_address(to_compare.ip_address))
00571       && !istring(hostname) && !istring(to_compare.hostname) )
00572     return true;
00573   if ( (is_nil_address(ip_address) && is_nil_address(to_compare.ip_address))
00574       && (istring(hostname).iequals(to_compare.hostname)) )
00575     return true;
00576   if (is_nil_address(ip_address)) return false;
00577   if (is_nil_address(to_compare.ip_address)) return false;
00578 
00579   // check that the bytes don't differ for the IP address.
00580   for (int i = 0; i < ADDRESS_SIZE; i++)
00581     if (ip_address[i] != to_compare.ip_address[i])
00582       return false;  // we have a loser.
00583 
00584   // they could still be different addresses if the hostnames differ...
00585 
00586   if (istring(hostname).t() && istring(to_compare.hostname).t()) {
00587     // name comparison.
00588     if (istring(hostname).lower() != istring(to_compare.hostname).lower())
00589       return false;
00590   }
00591 
00592   return true;
00593     // all bytes and host were identical, so it's the same address.
00594 }
00595 
00596 bool internet_address::same_port(const address_base &compare_in) const
00597 {
00598   CAST_UP(internet_address);
00599   return port == to_compare.port;
00600 }
00601 
00602 bool internet_address::shareable(const address_base &) const
00603 { return true; }
00604 
00605 bool internet_address::detokenize(const istring &info)
00606 {
00607   FUNCDEF("detokenize");
00608   LOADER_ENTRY;
00609   // either IP address or host must be specified.
00610 
00611   FIND("address", addr);
00612 #ifdef DEBUG_ADDRESS
00613   LOG(istring("info is ") + info + istring('.'));
00614   LOG(istring("addr is ") + addr);
00615 #endif
00616   byte_array ip_found;
00617   if (addr.t()) {
00618     // this bit rips off successive bytes from the string until the internet
00619     // address is filled out.  ignores any erroneous strings.
00620     for (int i = 0; i < ADDRESS_SIZE; i++) {
00621 #ifdef DEBUG_ADDRESS
00622       LOG(istring("ip curr: ") + addr);
00623 #endif
00624       int current_byte = addr.convert(int(0));
00625       ip_found += byte(current_byte);
00626 #ifdef DEBUG_ADDRESS
00627       LOG(isprintf("%d: %02x ", i, current_byte));
00628 #endif
00629       int indy = addr.find('.');
00630       addr.zap(0, indy);  // no error checking, but whatever.
00631     }
00632   }
00633 
00634   FIND("host", host);
00635   GRAB("port", port_t);  // this one's definitely needed.
00636   int port = port_t.convert(0);
00637   fill(ip_found, host, port);
00638 #ifdef DEBUG_ADDRESS
00639   LOG(istring("tcp/ip address found::: ") + text_form());
00640 #endif
00641   LOADER_EXIT;
00642   return true;
00643 }
00644 
00645 istring internet_address::tokenize() const
00646 {
00647   FUNCDEF("tokenize");
00648   STORER_ENTRY;
00649 #ifdef DEBUG_ADDRESS
00650   LOG(istring(isprintf("host eval is %d for %s",
00651       istring(hostname).t(), hostname));
00652 #endif
00653   if (istring(hostname).t()) ADD("host", hostname);
00654   bool print_ip = false;
00655   for (int i = 0; i < ADDRESS_SIZE; i++) if (ip_address[i]) print_ip = true;
00656   if (print_ip) {
00657     istring ip_addr;
00658     for (int i = 0; i < ADDRESS_SIZE; i++)
00659       ip_addr += isprintf("%d", int(ip_address[i])) + istring(".");
00660     ip_addr.zap(ip_addr.end(), ip_addr.end());  // remove last period. 
00661     ADD("address", ip_addr);
00662   }
00663   ADD("port", isprintf("%d", int(port)));
00664 #ifdef DEBUG_ADDRESS
00665   LOG(istring("your toke's currently ") + fred.text_form());
00666 #endif
00667   DUMP_EXIT;
00668 }
00669 
00670 // by Gary Hardley.
00671 // fixes by CAK 6/26/2002.
00672 bool internet_address::is_valid_internet_address(const istring &to_check,
00673     byte_array &ip_form, bool &all_zeros)
00674 {
00675   istring tmpstr = to_check;  // temporary copy of the given address string.
00676   all_zeros = true;  // default to true until proven otherwise.
00677   ip_form.reset();  // empty the address.
00678 
00679   // get the first part of the address.
00680   char *p = strtok(tmpstr.s(), ".");
00681 
00682   int index = 0;
00683   while (p && (index < ADDRESS_SIZE)) {
00684     int nTemp = istring(p).convert(-1);
00685 
00686     // is this part of the string a valid number between 0 & 255?
00687     if ( (nTemp < 0) || (nTemp > 255) ) return false;  // no.
00688 
00689     // yes, assign the number to the next address byte.
00690     ip_form += (byte)nTemp;
00691 
00692     // get the next part of the string
00693     p = strtok(NIL, ".");
00694   }
00695 
00696   // if p is non-null, there was extra stuff at the end, so return false.
00697   if (p) return false;
00698 
00699   for (int i = 0; i < ip_form.length(); i++)
00700     if (ip_form[i]) { all_zeros = false; break; }
00701 
00702   return ip_form.length() == ADDRESS_SIZE;
00703 }
00704 
00705 bool internet_address::valid_address(const istring &to_check)
00706 {
00707   byte_array addr;
00708   bool all_zeros;
00709   return is_valid_internet_address(to_check, addr, all_zeros);
00710 }
00711 
00712 istring internet_address::ip_address_text_form(const byte_array &ip_address)
00713 {
00714   return isprintf("%d.%d.%d.%d", int(ip_address[0]),
00715       int(ip_address[1]), int(ip_address[2]), int(ip_address[3]));
00716 }
00717 
00718 #ifndef EMBEDDED_BUILD
00719 
00721 
00722 serial_port_address::serial_port_address() { fill(1, 9600, 8, 'N', 1); }
00723 
00724 serial_port_address::serial_port_address(int port_in, int baud_rate_in,
00725     byte data_bits_in, char parity_in, byte stop_bits_in)
00726 { fill(port_in, baud_rate_in, data_bits_in, parity_in, stop_bits_in); }
00727 
00728 address_base *serial_port_address::create_copy() const
00729 {
00730   return new serial_port_address(port, baud_rate, data_bits, parity, stop_bits);
00731 }
00732 
00733 machine_uid serial_port_address::convert() const { return machine_uid(); }
00734 
00735 istring serial_port_address::GET_DSR() { return "get_dsr"; }
00736 
00737 istring serial_port_address::GET_CTS() { return "get_cts"; }
00738 
00739 istring serial_port_address::SET_DTR() { return "set_dtr"; }
00740 
00741 istring serial_port_address::SET_RTS() { return "set_rts"; }
00742 
00743 istring serial_port_address::USE_MARK_SPACE() { return "mark_space"; }
00744 
00745 istring serial_port_address::text_form() const
00746 {
00747   return isprintf("[port %d, baud %d, data %d, parity %c, stop %d]",
00748       port, baud_rate, int(data_bits), parity, int(stop_bits));
00749 }
00750 
00751 bool serial_port_address::same_host(const address_base &) const
00752 { return true; }
00753 
00754 bool serial_port_address::same_port(const address_base &compare_in) const
00755 {
00756   CAST_UP(serial_port_address);
00757   return port == to_compare.port;
00758 }
00759 
00760 bool serial_port_address::shareable(const address_base &compare_in) const
00761 {
00762   CAST_UP(serial_port_address);
00763   if (baud_rate != to_compare.baud_rate) return false;
00764   if (data_bits != to_compare.data_bits) return false;
00765   if (parity != to_compare.parity) return false;
00766   if (stop_bits != to_compare.stop_bits) return false;
00767   return true;
00768 }
00769 
00770 int serial_port_address::packed_size() const
00771 {
00772   return sizeof(port) + sizeof(baud_rate) + sizeof(data_bits)
00773       + sizeof(stop_bits)
00774       + 1;  // one byte for parity.
00775 }
00776 
00777 void serial_port_address::pack(byte_array &packed_form) const
00778 {
00779   attach(packed_form, port);
00780   attach(packed_form, baud_rate);
00781   attach(packed_form, data_bits);
00782   attach(packed_form, stop_bits);
00783   packed_form += byte_array(1, (byte *)&parity);
00784 }
00785 
00786 bool serial_port_address::unpack(byte_array &packed_form)
00787 {
00788   if (u_int(packed_form.length()) < sizeof(port) + sizeof(baud_rate)
00789       + sizeof(data_bits) + sizeof(stop_bits) + 1)
00790     return false;
00791   if (!detach(packed_form, port)) return false;
00792   if (!detach(packed_form, baud_rate)) return false;
00793   if (!detach(packed_form, data_bits)) return false;
00794   if (!detach(packed_form, stop_bits)) return false;
00795   parity = packed_form[0];
00796   packed_form.zap(0, 0);
00797   return true;
00798 }
00799 
00800 void serial_port_address::fill(int port_in, int baud_rate_in,
00801     byte data_bits_in, char parity_in, byte stop_bits_in)
00802 {
00803   port = port_in;
00804   baud_rate = baud_rate_in;
00805   data_bits = data_bits_in;
00806   // make sure the parity looks right.
00807   parity = (istring(parity_in, 1).upper())[0];
00808   stop_bits = stop_bits_in;
00809 }
00810 
00811 bool serial_port_address::detokenize(const istring &info)
00812 {
00813   LOADER_ENTRY;
00814   GRAB("port", port);  // necessary.
00815   GRAB("baud", baud);  // necessary.
00816   FIND("parity", parity);  // optional.
00817   FIND("data", data);  // optional.
00818   FIND("stop", stop);  // optional.
00819   fill(port.convert(0), baud.convert(0), byte(data.convert(8)),
00820       parity[0], byte(stop.convert(1)));
00821   LOADER_EXIT;
00822   return true;
00823 }
00824 
00825 istring serial_port_address::tokenize() const
00826 {
00827   STORER_ENTRY;
00828   ADD("port", isprintf("%d", int(port)));
00829   ADD("baud", isprintf("%d", baud_rate));
00830   ADD("parity", istring(parity, 1));
00831   ADD("data", isprintf("%d", int(data_bits)));
00832   ADD("stop", isprintf("%d", int(stop_bits)));
00833   DUMP_EXIT;
00834 }
00835 
00837 
00838 ipc_address::ipc_address() { fill("", ""); }
00839 
00840 ipc_address::ipc_address(const istring &service, const istring &topic)
00841 { fill(service, topic); }
00842 
00843 machine_uid ipc_address::convert() const { return machine_uid(); }
00844 
00845 void ipc_address::fill(const istring &service_in, const istring &topic_in)
00846 {
00847   service_in.stuff(service, MAXIMUM_IPC_NAME_LENGTH - 1);
00848   topic_in.stuff(topic, MAXIMUM_IPC_NAME_LENGTH - 1);
00849 }
00850 
00851 int ipc_address::packed_size() const
00852 {
00853   return 2 * (sizeof(int) + MAXIMUM_IPC_NAME_LENGTH);
00854 }
00855 
00856 void ipc_address::pack(byte_array &packed_form) const
00857 {
00858   packed_form += byte_array(MAXIMUM_IPC_NAME_LENGTH, (byte *)service);
00859   packed_form += byte_array(MAXIMUM_IPC_NAME_LENGTH, (byte *)topic);
00860 }
00861 
00862 bool ipc_address::unpack(byte_array &packed_form)
00863 {
00864