#ifndef __XRDNETUTILS_HH__
#define __XRDNETUTILS_HH__
/******************************************************************************/
/* */
/* X r d N e t U t i l s . h h */
/* */
/* (c) 2013 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
#include
#include
#include
#include "XrdOuc/XrdOucEnum.hh"
class XrdOucTList;
class XrdNetAddr;
union XrdNetSockAddr;
namespace XrdNetSpace {struct hpSpec;}
class XrdNetUtils
{
public:
//------------------------------------------------------------------------------
//! Decode an "encoded" ipv6/4 address and place it "sockaddr" type structure.
//!
//! @param sadr address of the union that will hold the results.
//! @param buff address of buffer that holds the encoding.
//! @param blen length of the string (it need not be null terminated).
//!
//! @return > 0 the port number in host byte order.
//! = 0 the port number was not set.
//! < 0 the encoding was not correct.
//------------------------------------------------------------------------------
static int Decode(XrdNetSockAddr *sadr, const char *buff, int blen);
//------------------------------------------------------------------------------
//! Encode the address and return it in a supplied buffer.
//!
//! @param sadr address of the union that holds the IPV4/6 address.
//! @param buff address of buffer to hold the null terminated encoding.
//! @param blen length of the buffer. It6 should be at least 40 bytes.
//! @param port optional port value to use as opposed to the one present
//! in sockaddr sadr. The port must be in host order.
//!
//! @return > 0 the length of the encoding less the null byte.
//! = 0 current address format not supported for encoding.
//! < 0 buffer is too small; abs(retval) bytes needed.
//------------------------------------------------------------------------------
static int Encode(const XrdNetSockAddr *sadr, char *buff, int blen, int port=-1);
//------------------------------------------------------------------------------
//! Version 1: Return multiple addresses associated with a host or IP address.
//!
//! @param hSpec -> convert specification to addresses. Valid formats:
//! IP.v4: nnn.nnn.nnn.nnn[:]
//! IP.v6: [ipv6_addr][:]
//! IP.xx: name[:port] xx is determined by getaddrinfo()
//! @param aListP place where the pointer to the returned array of XrdNetAddr
//! objects is to be placed. Set to zero if none returned. The
//! caller must delete this array when no longer needed.
//! @param aListN place where the number of elements in aListP are to be
//! returned.
//! @param opts Options on what to return. Choose one of:
//! allIPMap - all IPv6 and mapped IPv4 addrs (default)
//! allIPv64 - all IPv6 and unmapped IPv4 addrs
//! allV4Map - all mapped IPV4 addrs.
//! onlyIPv6 - only IPv6 addrs
//! onlyIPv4 - only unmapped IPv4 addrs
//! prefIPv6 - only IPv6 addrs; if none, mapped IPv4 addrs
//! prefAuto - Returns addresses based on configured non-local
//! interfaces. The returned addresses will be
//! normally useable on this host and may be IPv4,
//! IPv6, mapped IPv4, or a mixture.
//! The above may be or'd with one or more of the following:
//! onlyUDP - only addrs valid for UDP connections else TCP
//! order46 - List IPv4 addresses (mapped or native) first.
//! order64 - List IPv6 addresses first.
//! @param pNum >= 0 uses the value as the port number regardless of what
//! is in hSpec, should it be supplied. However, if is
//! present, it must be a valid port number.
//! < 0 uses the positive value as the port number if the
//! port number has not been specified in hSpec.
//! **** When set to PortInSpec(the default, see below) the
//! port number/name must be specified in hSpec. If it is
//! not, an error is returned.
//! **** When set to NoPortRaw then hSpec does not contain a
//! port number and is a host name, IPv4 address, or an
//! IPv6 address *without* surrounding brackets.
//!
//! @return Success: 0 with aListN set to the number of elements in aListP.
//! Failure: the error message text describing the error and aListP
//! and aListN is set to zero.
//------------------------------------------------------------------------------
enum AddrOpts {allIPMap= 0, allIPv64= 1, allV4Map= 2,
onlyIPv6= 3, onlyIPv4= 4, prefIPv6= 8,
prefAuto= 16, order46 = 32, order64 = 64,
onlyUDP =128
};
static const int PortInSpec = (int)0x80000000;
static const int NoPortRaw = (int)0xC0000000;
static
const char *GetAddrs(const char *hSpec, XrdNetAddr *aListP[], int &aListN,
AddrOpts opts=allIPMap, int pNum=PortInSpec);
//------------------------------------------------------------------------------
//! Version 2: Return multiple addresses associated with a host or IP address.
//!
//! @param hSpec Reference to address specification (see version 1).
//! @param aVec Reference to the vector to contain addresses.
//! @param ordn Pointer to where the partition ordinal is to be stored.
//! @param opts Options on what to return (see version 1).
//! @param pNum Port number argument (see version 1).
//!
//! @return Success: 0 is returned. When ordn is not nil, the number of IPv4
//! entries (for order46) or IPv6 (for order64) entries that
//! appear in the front of the vector. If ordering is not
//! specified, the value is set to the size of the vector.
//! Failure: the error message text describing the error and aVec is
//! cleared (i.e. has no elements).
//------------------------------------------------------------------------------
static
const char *GetAddrs(const std::string &hSpec, std::vector &aVec,
int *ordn=0, AddrOpts opts=allIPMap, int pNum=PortInSpec);
//------------------------------------------------------------------------------
//! Version 3: Return multiple addresses associated with a list of host or
//! IP addresses.
//!
//! @param hSVec vector of address specification (see version 1). Note that
//! this version requires hSVec entries to have a port number.
//! @param aVec Reference to the vector to contain addresses.
//! @param ordn Pointer to where the partition ordinal is to be stored.
//! @param opts Options on what to return (see version 1).
//! @param rotNum The rotation factor to order addresses in the result.
//! @param force When true resolution errors are ignored.
//!
//! @return Success: 0 is returned. When ordn is not nil, the number of IPv4
//! entries (for order46) or IPv6 (for order64) entries that
//! appear in the front of the vector. If ordering is not
//! specified, the value is set to the size of the vector.
//! Failure: the error message text describing the error and aVec is
//! cleared (i.e. has no elements).
//------------------------------------------------------------------------------
static
const char *GetAddrs(std::vector &hSVec,
std::vector &aVec,
int *ordn=0, AddrOpts opts=allIPMap,
unsigned int rotNum=0, bool force=false);
//------------------------------------------------------------------------------
//! Obtain connection information from a socket.
//!
//! @param fd The file descriptor of the socket whose address is to be
//! converted. The sign of the fd indicates which address:
//! fd > 0 the peer address is used (i.e. getpeername)
//! fd < 0 the local address is used (i.e. getsockname)
//! @param theAddr pointer to a buffer of theAlen bytes where the text
//! version of the IP address is to be returned. The text
//! uses the actual native address format. If theAddr is
//! nil or theAlen is not positive, only the port and
//! address type are returned.
//! @param theALen length of the theAddr buffer.
//! @param theType either the character 4 (IPv4) or 6 (IPv6) is returned.
//! corrresponding to the address family. Note that should
//! be AF_INET6 but the address is mapped, '4' is returned.
//!
//! @return Success: >= 0 corresponding to the port number.
//! @return Failure: < 0 corresponding to -errno.
//------------------------------------------------------------------------------
static
int GetSokInfo(int fd, char *theAddr, int theALen, char &theType);
//------------------------------------------------------------------------------
//! Obtain an easily digestable list of hosts. This is the list of up to eight
//! unique aliases (i.e. with different addresses) assigned to a base hostname.
//!
//! @param hSpec the host specification suitable for XrdNetAddr.Set().
//! @param hPort When >= 0 specified the port to use regardless of hSpec.
//! When < 0 the port must be present in hSpec.
//! @param hWant Maximum number of list entries wanted. If hWant is greater
//! that eight it is set eigth.
//! @param sPort If not nil, the *sPort will be set to hPort if and only if
//! the IP address in one of the entries matches the host
//! address. Otherwise, the value is unchanged.
//! @param eText When not nil, is where to place error message text.
//!
//! @return Success: Pointer to a list of XrdOucTList objects where
//! p->val is the port number
//! p->text is the host name.
//! The list of objects belongs to the caller.
//! Failure: A nil pointer is returned. If eText is supplied, the error
//! message, in persistent storage, is returned.
//------------------------------------------------------------------------------
static
XrdOucTList *Hosts(const char *hSpec, int hPort=-1, int hWant=8, int *sPort=0,
const char **eText=0);
//------------------------------------------------------------------------------
//! Convert an IP address/port (V4 or V6) into the standard V6 RFC ASCII
//! representation: "[address]:port".
//!
//! @param sAddr Address to convert. This is either sockaddr_in or
//! sockaddr_in6 cast to struct sockaddr.
//! @param bP points to a buffer large enough to hold the result.
//! A buffer 64 characters long will always be big enough.
//! @param bL the actual size of the buffer.
//! @param opts Formating options:
//! noPort - does not suffix the port number with ":port".
//! oldFmt - use the deprecated format for an IPV4 mapped
//! address: [::d.d.d.d] vs [::ffff:d.d.d.d].
//!
//! @return Success: The length of the formatted address is returned.
//! @return Failure: Zero is returned and the buffer state is undefined.
//! Failure occurs when the buffer is too small or the address family
//! (sAddr->sa_family) is neither AF_INET nor AF_INET6.
//------------------------------------------------------------------------------
static const int noPort = 1;
static const int oldFmt = 2;
static int IPFormat(const struct sockaddr *sAddr, char *bP, int bL, int opts=0);
//------------------------------------------------------------------------------
//! Convert an IP socket address/port (V4 or V6) into the standard V6 RFC ASCII
//! representation: "[address]:port".
//!
//! @param fd The file descriptor of the socket whose address is to be
//! converted. The sign of the fd indicates which address:
//! fd > 0 the peer address is used (i.e. getpeername)
//! fd < 0 the local address is used (i.e. getsockname)
//! @param bP points to a buffer large enough to hold the result.
//! A buffer 64 characters long will always be big enough.
//! @param bL the actual size of the buffer.
//! @param opts Formating options:
//! noPort - does not suffix the port number with ":port".
//! oldFmt - use the deprecated format for an IPV4 mapped
//! address: [::d.d.d.d] vs [::ffff:d.d.d.d].
//!
//! @return Success: The length of the formatted address is returned.
//! @return Failure: Zero is returned and the buffer state is undefined.
//! Failure occurs when the buffer is too small or the file
//! descriptor does not refer to an open socket.
//------------------------------------------------------------------------------
static int IPFormat(int fd, char *bP, int bL, int opts=0);
//------------------------------------------------------------------------------
//! Determine if a hostname matches a pattern.
//!
//! @param hName the name of the host.
//! @param pattern the pattern to match against. The pattern may contain one
//! If the pattern contains a single asterisk, then the prefix
//! of hName is compared with the characters before the '*' and
//! the suffix of hName is compared with the character after.
//! If the pattern ends with a plus, the all then pattern is
//! taken as a hostname (less '+') and expanded to all possible
//! hostnames and each one is compared with hName. If the
//! pattern contains both, the asterisk rule is used first.
//! If it contains neither then strict equality is used.
//!
//! @return Success: True, the pattern matches.
//! Failure: False, no match found.
//------------------------------------------------------------------------------
static bool Match(const char *hName, const char *pattern);
//------------------------------------------------------------------------------
//! Get the fully qualified name of the current host.
//!
//! @param eName The name to be returned when the host name or its true
//! address could not be returned. The pointer may be nil.
//! @param eText When supplied will hold 0 if no errors occurred or error
//! message text, in persistent storage, describing why the
//! error-triggered alternate name was returned.
//! If it contains neither then strict equality is used.
//!
//! @return An strdup() copy of the host name, address , or eName; unless eName
//! is nil, in which case a nil pointer is returned. The caller is
//! responsible for freeing any returned string using free().
//------------------------------------------------------------------------------
static char *MyHostName(const char *eName="*unknown*", const char **eText=0);
//------------------------------------------------------------------------------
//! Get the supported network protocols.
//!
//! @param netqry An NetType enum specifying the protocol to inspect.
//! @param eText When not nil, is where to place error message text.
//!
//! @return One the the NetProt enums (see below). When hasNone is returned
//! and eText is not nill it will point to a static string that gives
//! the reason. If the reason is a null string, the query was successful
//! but returned no matching protocols.
//------------------------------------------------------------------------------
enum NetProt {hasNone = 0, //!< Unable to determine available protocols
hasIPv4 = 1, //]:", ":", or ":".
//! @param hName place where the starting address of the host is placed.
//! @param hNend place where the ending address+1 is placed. This will
//! point to either ']', ':', or a null byte.
//! @param hPort place where the starting address of the port is placed.
//! If no ":port" was found, this will contain *hNend.
//! @param hPend place where the ending address+1 is placed. If no port
//! If no ":port" was found, this will contain *hNend.
//!
//! @return Success: True.
//! Failure: False, hSpec is not valid. Some output parameters may have
//! been set but shlould be ignored.
//------------------------------------------------------------------------------
static bool Parse(const char *hSpec, const char **hName, const char **hNend,
const char **hPort, const char **hPend);
//------------------------------------------------------------------------------
//! Obtain the numeric port associated with a file descriptor.
//!
//! @param fd the file descriptor number.
//! @param eText when not null, the reason for a failure is returned.
//!
//! @return Success: The positive port number.
//! Failure: 0 is returned and if eText is not null, the error message.
//------------------------------------------------------------------------------
static int Port(int fd, const char **eText=0);
//------------------------------------------------------------------------------
//! Obtain the protocol identifier.
//!
//! @param pName the name of the protocol (e.g. "tcp").
//!
//! @return The protocol identifier.
//------------------------------------------------------------------------------
static int ProtoID(const char *pName);
//------------------------------------------------------------------------------
//! Obtain the numeric port corresponding to a symbolic name.
//!
//! @param sName the name of the service or a numeric port number.
//! @param isUDP if true, returns the UDP service port o/w the TCP service
//! @param eText when not null, the reason for a failure is returned.
//!
//! @return Success: The positive port number.
//! Failure: 0 is returned and if eText is not null, the error message.
//------------------------------------------------------------------------------
static int ServPort(const char *sName, bool isUDP=false, const char **eText=0);
//------------------------------------------------------------------------------
//! Set the family and hints to be used in GetAddrs() with prefAuto. This is
//! used within this class and by XrdNetAddr when the IP mode changes. It is
//! meant for internal use only.
//!
//! @param aOpts Is one of the following from the AddrOpts enum:
//! allIPMap - Use IPv6 and mapped IPv4 addrs (default)
//! onlyIPv4 - Use only IPv4 addresses.
//! prefAuto - Determine proper options based on configuration.
//!
//! @return The getaddrinfo() hints value that should be used.
//------------------------------------------------------------------------------
static int SetAuto(AddrOpts aOpts=allIPMap);
//------------------------------------------------------------------------------
//! Check if whether or not a host name represents more than one unique host.
//!
//! @param hSpec the host specification suitable for XrdNetAddr.Set().
//! @param eText When not nil, is where to place error message text.
//!
//! @return True is this is a simple single host. False if the name represensts
//! more than one single host.
//------------------------------------------------------------------------------
static bool Singleton(const char *hSpec, const char **eText=0);
static bool ConnectWithTimeout(int sockfd, const struct sockaddr* clientAddr, size_t clientAddrLen,uint32_t timeout_sec, std::stringstream & errMsg);
//------------------------------------------------------------------------------
//! Constructor
//------------------------------------------------------------------------------
XrdNetUtils() {}
//------------------------------------------------------------------------------
//! Destructor
//------------------------------------------------------------------------------
~XrdNetUtils() {}
private:
static void FillAddr(XrdNetSpace::hpSpec &aBuff, XrdNetAddr *aVec,
int *ordn=0, unsigned int rotNum=0);
static
const char *GetAInfo(XrdNetSpace::hpSpec &aBuff);
static void GetHints(XrdNetSpace::hpSpec &aBuff, AddrOpts opts);
static
const char *GetHostPort(XrdNetSpace::hpSpec &aBuff, const char *hSpec, int pNum);
static
const char *getMyFQN(const char *&myDom);
static int setET(const char **errtxt, int rc);
static bool SetSockBlocking(int sockfd, bool blocking, std::stringstream & errMsg);
static int autoFamily;
static int autoHints;
};
XRDOUC_ENUM_OPERATORS(XrdNetUtils::AddrOpts)
#endif