/* * Ivy League * * INET Addresses * * Copyright 1990-2000 * Laboratoire de Recherche en Informatique (LRI) * Centre d'Etudes de la Navigation Aerienne (CENA) * * original code by Michel Beaudouin-Lafon, * modified by Stephane Chatty * * $Id$ * */ #include "InetAddress.h" #include #include #ifdef __osf__ extern "C" { unsigned short htons (unsigned short); unsigned short ntohs (unsigned short); int gethostname (char*, int); #endif #include #ifdef __osf__ } #endif // constructors for inet addresses // inet address specified by: // hostname / port# (ANY if hostname is NIL, LOOPBACK if hostname is "") // hostid / port# (predefined hostids ANYADDR, ...) // todo: // hostname / service name ?? // /*? IvlInetAddresses should only be allocated with new because they can be deleted and reallocated by \type{IvlSocket} class. ?*/ IvlInetAddress :: IvlInetAddress () : IvlAddress (), HostName (), HasHostName (false) { } /*? Construct an inet address, from a hostname and a port number. The address is valid only if the host is valid. If \var{host} is the empty string, the loopback host is used; if it is the nil pointer, the wildcard (INADDR_ANY) is used. If the port number is 0, it will be allocated by the system. ?*/ IvlInetAddress :: IvlInetAddress (const char* name, sword port) : IvlAddress (), HostName (), HasHostName (false) { if (name && *name) { struct hostent *host = gethostbyname (name); if (! host) return; memcpy (&Addr.sin_addr, host->h_addr, host->h_length); } else Addr.sin_addr.s_addr = name ? INADDR_LOOPBACK : INADDR_ANY; Addr.sin_family = AF_INET; Addr.sin_port = htons (port); Valid = true; } /*? Construct an inet address, from a host id (internet address) and a port number. If the port number is 0, it is assigned by the system. The host ids \var{^{ANYADDR}}, \var{^{LOOPBACK}} and \var{^{BROADCAST}} are predefined. \var{ANYADDR} is used to receive messages from anywhere. \var{LOOPBACK} is the local host address. \var{BROADCAST} makes it possible to send data to all the hosts of a local area network. ?*/ IvlInetAddress :: IvlInetAddress (lword host, sword port) : IvlAddress (), HostName (), HasHostName (false) { Addr.sin_family = AF_INET; Addr.sin_port = htons (port); Addr.sin_addr.s_addr = htonl (host); Valid = true; } /*?nodoc?*/ IvlInetAddress :: ~IvlInetAddress () { } /*?nodoc?*/ int IvlInetAddress :: Family () { return AF_INET; } /*?nodoc?*/ int IvlInetAddress :: Length () { return sizeof (Addr); } /*?nodoc?*/ SockAddr* IvlInetAddress :: GetSockAddr () { return (SockAddr*) &Addr; } /*? This is a global function (static member of class \typ{IvlInetAddress}. It returns the internet address of the local host. This is different from the predefined address \var{LOOPBACK}: \var{LOOPBACK} is the same constant on each machine, so that it cannot be communicated across the network. The value returned by \fun{LoopBack} is the unique internet address of the local host. Thus it can be communicated to another host across the network. ?*/ lword IvlInetAddress :: LoopBack () { static lword loopback = 0; if (loopback) return loopback; struct hostent *host; #if 0 char name [128]; gethostname (name, sizeof (name)); host = gethostbyname (name); #else struct utsname un; if (uname (&un) < 0) { Error (ErrFatal, "address", "cannot get name of local host"); return 0; } host = gethostbyname (un.nodename); #endif if (! host) { Error (ErrFatal, "address", "cannot get address of local host"); return 0; } return loopback = * ((lword *) host->h_addr); } /*? Return the host number of the address. ?*/ lword IvlInetAddress :: Host () { return ntohl (Addr.sin_addr.s_addr); } /*? Return the port number of the address. ?*/ sword IvlInetAddress :: Port () { return ntohs (Addr.sin_port); } /*? Return a const string representing the hostname part of the address if any or NULL if it does not exist (INADDR_ANY, INADDR_LOOPBACK or INADDR_BROADCAST). This is an interface to unix \fun{gethostbyaddr} system call. ?*/ const char* IvlInetAddress :: GetHostName () { struct hostent *host; unsigned long saddr; if (HasHostName) return HostName; saddr = Addr.sin_addr.s_addr; host = gethostbyaddr ((char*) &saddr, sizeof (long), AF_INET); if (host) HostName = host->h_name; #if 0 } else HostName = GetNoHostName(); #endif else { struct utsname un; if (uname (&un) < 0) { Error (ErrFatal, "GetHostName", "cannot get name of local host"); HostName = 0; } HostName = un.nodename; } HasHostName = true; return HostName; } /*?nodoc?*/ const char* IvlInetAddress :: GetNoHostName () { const char* hname; unsigned long saddr = Addr.sin_addr.s_addr; if (saddr == INADDR_ANY) hname = "ANY"; else if (saddr == INADDR_LOOPBACK) hname = "LOOPBACK"; else if (saddr == INADDR_BROADCAST) hname = "BROADCAST"; else hname = "???"; return hname; } /*? Return a newly allocated \typ{char*} pointing to a string representing the internet address as "hostname:port". If no host name can be found then it can be "ANY" (INADDR_ANY), "LOOPBACK" (INADDR_LOOPBACK), "BROADCAST" (INADDR_BROADCAST) or "???". If argument \var{buf} is not null, return it's value in buf and do not allocate any memory. ?*/ char* IvlInetAddress :: StrRepr (char* buf) { const char* hname; if (HasHostName) { hname = HostName; if (!hname) hname = GetNoHostName (); } else hname = GetHostName (); if (! buf) buf = new char [ strlen(hname) + 2 + 7 ]; sprintf (buf, "%s::%d",hname, ntohs (Addr.sin_port)); return buf; }