Module: sockets-internals Author: Toby Synopsis: Internet address objects Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND ignorable(%address-value-setter); // Wrappers for raw numeric internet addresses define open abstract primary class () end class; define sealed generic network-order (address :: ) => (network-order-address :: ); define sealed generic host-order (address :: ) => (host-order-address :: ); define open abstract primary class () slot %address-value :: , required-init-keyword: address:; end class; define sealed primary class () end class; define method network-order (the-address :: ) => (result :: ) the-address.%address-value end method; define method host-order (the-address :: ) => (result :: ) accessor-ntohl(the-address.%address-value) end method; define method as (the-class == , the-address :: ) => (result :: ) accessor-ipv4-address-to-presentation(the-address) end method; define sealed primary class () end class; define method network-order (the-address :: ) => (result :: ) accessor-htonl(the-address.%address-value) end method; define method host-order (the-address :: ) => (result :: ) the-address.%address-value end method; // class definition and initialization define open primary class () end class; // For now just delegate to define method make (class == , #rest initargs, #key) => (address-object :: ) apply(make, , initargs) end method make; define open generic host-name (the-address :: type-union(, )) => (the-name :: ); define open generic host-address (address-object :: type-union(, )) => (the-address :: ); define open generic numeric-host-address (address-object :: ) => (the-address :: ); define open generic all-addresses (address-object :: ) => (addresses :: ); define open generic aliases (address-object :: ) => (the-aliases :: ); define sealed class () slot %host-name :: false-or(), init-value: #f; slot %host-address :: false-or(), init-value: #f; slot %aliases :: false-or(), init-value: #f; slot %addresses :: false-or(), init-value: #f; constant slot address-family :: , init-value: $AF-INET; end class; define method initialize (new-address :: , #key address: initialization-address :: false-or(type-union(, )) = #f, name: initialization-name :: false-or() = #f, aliases: initialization-aliases :: false-or() = #f, addresses: initialization-addresses :: false-or() = #f) => () next-method(); // Ok, here is the story. If you give me an address: (or // addresses:) I will trust the rest of the information. Any // missing information will be filled in lazily by the accessors. // In particular this means that if you give me a name which isn't // the canonical name the name might change to the canonical name // under your feet. Tough. If you give a name and no address then // the address, and everything else gets filled in now, eagerly, and // the information will come from the host_ent structure returned // from gethostbyname. // If the address: keyword is defined if (initialization-address) /* compiler doesn't like this code new-address.%host-address := select (new-address by instance?) => initialization-address; => accessor-ipv4-presentation-to-address(initialization-address); end select; */ select (initialization-address by instance?) => new-address.%host-address := initialization-address; => new-address.%host-address := accessor-ipv4-presentation-to-address(initialization-address); end select; // Now just trust the rest. Maybe ought to check that the // sequences are will formed. Better might be to not document // anything but the name: and address: initializers. The rest // are really for when you are making an from // an existing . new-address.%host-name := initialization-name; new-address.%aliases := initialization-aliases; new-address.%addresses := initialization-addresses; elseif (initialization-addresses) new-address.%host-name := initialization-name; new-address.%host-address := initialization-address; new-address.%aliases := initialization-aliases; new-address.%addresses := initialization-addresses; elseif (initialization-name) // Ignore all of the other initializers, if any, use the // information from the network. Nyah-nyah. accessor-get-host-by-name(new-address, initialization-name); else error("make(: address: or name: keyword must be supplied."); end if; end method initialize; // Virtual slot accessors define method host-name (the-address :: ) => (result :: ) unless (the-address.%host-name) accessor-get-host-by-address(the-address) end unless; the-address.%host-name end method; define sealed method host-address (the-address :: ) => (result :: ) if (the-address.%host-address) accessor-ipv4-address-to-presentation(the-address.%host-address) elseif (the-address.%addresses) accessor-ipv4-address-to-presentation(the-address.%addresses.first) else error("internal error: doesn't have a valid host-address"); end if end method; define sealed method numeric-host-address (the-address :: ) => (result :: ) if (the-address.%host-address) the-address.%host-address elseif (the-address.%addresses) the-address.%addresses.first else error("internal error: doesn't have a valid host-address"); end if end method; define sealed method all-addresses (the-address :: ) => (result :: ) unless (the-address.%addresses) accessor-get-host-by-address(the-address) end unless; let numeric-addresses = the-address.%addresses; let vector-size = numeric-addresses.size; let result = make(, size: vector-size); // This is arguably unsafe since the various copied values might // conceivably be modified by somebody (and the modifications would // affect all the addresses. Copying everything would be // painful however. No way to make the collections read only. for (index from 0 below vector-size) result[index] := make(, name: the-address.%host-name, address: numeric-addresses[index], aliases: the-address.%aliases, addresses: the-address.%addresses); end for; result end method; /* define constant $loopback-address :: = make(, address: "127.0.0.1"); define constant $local-host-name :: = accessor-local-host-name(); define constant $local-host :: = make(, name: $local-host-name); */ // Define these as variables instead of constants. Put the // initialization in the start-trap function. Boo. Hiss. define variable $loopback-address :: false-or() = #f; define variable $local-host-name :: = ""; define variable $local-host :: false-or() = #f;