37 #include <netinet/in.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
59 int XrdNetUtils::autoFamily;
71 static const int ipv4Sz =
sizeof(
struct in_addr)*2+4;
72 static const int ipv6Sz =
sizeof(
struct in6_addr)*2+4;
73 char bval[
sizeof(
struct in6_addr)+2];
74 int isv6, n, i = 0, Odd = 0;
78 if (blen == ipv6Sz) isv6 = 1;
79 else if (blen == ipv4Sz) isv6 = 0;
85 {
if (*buff >=
'0' && *buff <=
'9') n = *buff-48;
86 else if (*buff >=
'a' && *buff <=
'f') n = *buff-87;
87 else if (*buff >=
'A' && *buff <=
'F') n = *buff-55;
89 if (Odd) bval[i++] |= n;
90 else bval[i ] = n << 4;
101 {sadr->
v6.sin6_family = AF_INET6;
102 memcpy(&(sadr->
v6.sin6_port), bval, 2);
103 memcpy(&(sadr->
v6.sin6_addr), &bval[2],
sizeof(
struct in6_addr));
105 sadr->
v4.sin_family = AF_INET;
106 memcpy(&(sadr->
v4.sin_port), bval, 2);
107 memcpy(&(sadr->
v4.sin_addr), &bval[2],
sizeof(
struct in_addr));
112 return static_cast<int>(ntohs(sadr->
v6.sin6_port));
122 static const char *hv =
"0123456789abcdef";
123 char *src, bval[
sizeof(
struct in6_addr)+2];
128 if (sadr->
Addr.sa_family == AF_INET6)
129 {src = (
char *)&(sadr->
v6.sin6_addr); asz =
sizeof(
struct in6_addr);}
130 else if (sadr->
Addr.sa_family == AF_INET)
131 {src = (
char *)&(sadr->
v4.sin_addr); asz =
sizeof(
struct in_addr); }
133 if (blen < (asz*2)+5)
return -((asz*2)+5);
137 if (port < 0) memcpy(bval, &(sadr->
v6.sin6_port), 2);
138 else {
short sPort = htons(
static_cast<short>(port));
139 memcpy(bval, &sPort, 2);
141 memcpy(&bval[2], src, asz);
146 for (i = 0; i < asz; i++)
147 {buff[j++] = hv[(bval[i] >> 4) & 0x0f];
148 buff[j++] = hv[ bval[i] & 0x0f];
161 #define OrderXX (XrdNetUtils::order46 | XrdNetUtils::order64)
163 #define SIN_PORT(x) ((struct sockaddr_in *)(x->ai_addr))->sin_port
195 int *ordn,
unsigned int rotNum)
197 struct addrinfo *aP, *nP[2];
203 {nP[0] = aInfo.
aiP4; aN[0] = aInfo.
aNum4;
210 for (
int k = 0; k < 2; k++)
212 if (sz && (aP = nP[k]))
213 {
int iBeg = rotNum % sz, iEnd = sz;
214 do {
for (
int i = iBeg; i < iEnd && aP; i++)
215 {
int pNum = int(
SIN_PORT(aP)) & 0x0000ffff;
219 iEnd = iBeg; iBeg = 0;
230 else *ordn = aInfo.
aNum6;
252 GetHints(aInfo,
opts);
256 if ((eText = GetHostPort(aInfo, hSpec, pNum))
257 || (eText = GetAInfo(aInfo)))
return eText;
265 FillAddr(aInfo, *aVec);
276 std::vector<XrdNetAddr> &aVec,
296 GetHints(aInfo,
opts);
300 if ((eText = GetHostPort(aInfo, hSpec.c_str(), pNum))
301 || (eText = GetAInfo(aInfo)))
return eText;
308 FillAddr(aInfo, aVec.data(), ordn);
319 std::vector<XrdNetAddr> &aVec,
int *ordn,
330 if (!hSVec.size())
return 0;
334 GetHints(aInfo,
opts);
338 for (
int i = 0; i < (int)hSVec.size(); i++)
339 {
if (((eText = GetHostPort(aInfo, hSVec[i].c_str(), PortInSpec))
340 || (eText = GetAInfo(aInfo))) && !force)
return eText;
347 FillAddr(aInfo, aVec.data(), ordn, rotNum);
361 struct addrinfo *last4 = 0, *last6 = 0, *xP = 0, *rP = 0, *nP;
362 unsigned short pNum =
static_cast<unsigned short>(aInfo.
port);
366 int rc = getaddrinfo(aInfo.
ipAddr, 0, &aInfo.
hints, &rP);
368 {
if (rP) freeaddrinfo(rP);
369 return (rc ? gai_strerror(rc) :
"host not found");
375 do {nP = rP->ai_next;
376 if (rP->ai_family == AF_INET6 || rP->ai_family == AF_INET)
378 bool v4mapped =
false;
379 if (rP->ai_family == AF_INET6)
380 {
struct sockaddr_in6 *ipv6 = (
struct sockaddr_in6 *)rP->ai_addr;
381 if (IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr))
382 {rP->ai_next = xP; xP = rP;
continue;}
383 v4mapped = IN6_IS_ADDR_V4MAPPED(&ipv6->sin6_addr);
385 if (aInfo.
noOrder || rP->ai_family == AF_INET || v4mapped)
386 {
if (last4) last4->ai_next = rP;
387 else aInfo.
aiP4 = rP;
391 if (last6) last6->ai_next = rP;
392 else aInfo.
aiP6 = rP;
397 }
else {rP->ai_next = xP; xP = rP;}
402 if (xP) freeaddrinfo(xP);
413 struct addrinfo &hints = aInfo.
hints;
417 memset(&hints, 0,
sizeof(hints));
418 hints.ai_socktype = (aInfo.
onlyUDP ? SOCK_DGRAM : SOCK_STREAM);
419 opts =
opts & ~(onlyUDP | order46 | order64);
421 {
case allIPMap: hints.ai_family = AF_INET6;
422 hints.ai_flags = AI_V4MAPPED | AI_ALL;
424 case allIPv64: hints.ai_family = AF_UNSPEC;
426 case allV4Map: hints.ai_family = AF_INET;
429 case onlyIPv6: hints.ai_family = AF_INET6;
431 case onlyIPv4: hints.ai_family = AF_INET;
433 case prefIPv6: hints.ai_family = AF_INET6;
434 hints.ai_flags = AI_V4MAPPED;
436 case prefAuto: hints.ai_family = autoFamily;
437 hints.ai_flags = autoHints;
439 default: hints.ai_family = AF_INET6;
440 hints.ai_flags = AI_V4MAPPED | AI_ALL;
450 const char *hSpec,
int pNum)
452 static const char *badHS =
"invalid host specification";
453 const char *hnBeg, *hnEnd, *pnBeg, *pnEnd;
457 if (!hSpec)
return badHS;
462 if (pNum == NoPortRaw)
463 {hnBeg = aInfo.
ipAdr;
466 if (!Parse(aInfo.
ipAdr, &hnBeg, &hnEnd, &pnBeg, &pnEnd))
return badHS;
469 {
if (pNum == PortInSpec)
return "port not specified";
470 aInfo.
port = abs(pNum);
474 int n = ServPort(pnBeg, aInfo.
onlyUDP, &eText);
475 if (!n)
return eText;
476 if (pNum < 0) aInfo.
port = n;
482 if (aInfo.
hints.ai_family == AF_INET6 && aInfo.
ipAdr[0] !=
'['
484 {memcpy(aInfo.
ipMap,
"::ffff:", 7);
486 }
else aInfo.
ipAddr = hnBeg;
505 unsigned short thePort;
509 rc = (fd > 0 ? getpeername( fd, &theIP.
Addr, &addrSize)
510 : getsockname(-fd, &theIP.
Addr, &addrSize));
511 if (rc)
return -errno;
515 if (ipAddr.
Set(&theIP.
Addr))
return -EAFNOSUPPORT;
524 if (theAddr && theALen > 0
530 thePort = htons((theIP.
Addr.sa_family == AF_INET
531 ? theIP.
v4.sin_port : theIP.
v6.sin6_port));
532 return static_cast<int>(thePort);
541 int *sPort,
const char **eText)
543 static const int hMax = 8;
546 const char *etext, *hName;
552 if (hWant > hMax) hWant = hMax;
553 else if (hWant < 1) hWant = 1;
557 if ((etext = aList[0].Set(hSpec, numIP, hWant, hPort)))
558 {
if (eText) *eText = etext;
565 for (i = 0; i < numIP; i++)
566 {
if (sPort && myAddr.Same(&aList[i]))
567 {*sPort = aList[i].
Port(); sPort = 0;}
568 hName = aList[i].
Name(
"");
569 for (k = 0; k < i; k++) {
if (!strcmp(hName, aList[k].Name(
"")))
break;}
570 if (k >= i) tList =
new XrdOucTList(hName, aList[i].Port(), tList);
575 if (eText) *eText = (tList ? 0 :
"unknown processing error");
584 char *bP,
int bL,
int opts)
591 if (theAddr.
Set(sAddr))
return 0;
609 rc = (fd > 0 ? getpeername( fd, &theIP.
Addr, &addrSize)
610 : getsockname(-fd, &theIP.
Addr, &addrSize));
615 return IPFormat(&theIP.
Addr, bP, bL,
opts);
624 static const int maxIP = 16;
630 if (!strcmp(HostPat, HostName))
return true;
634 if ((mval = index(HostPat, (
int)
'*')))
635 { i = mval - HostPat; mval++;
636 k = strlen(HostName); j = strlen(mval);
638 || strncmp(HostName, HostPat,i)
639 || strncmp((HostName+k-j),mval,j))
return false;
646 if (i && HostPat[i-1] ==
'+')
649 if (i >= (
int)
sizeof(hBuff))
return false;
650 memcpy(hBuff, HostPat, i-1);
652 if (InetAddr[0].Set(hBuff, i, maxIP, 0))
return false;
653 while(i--)
if ((mval = InetAddr[i].Name()) && !strcmp(mval, HostName))
672 if (!fqn) fqn = eName;
673 return (fqn ? strdup(fqn) : 0);
691 if (netquery != qryINET && netquery != qryINIF)
692 {
if (eText) *eText =
"unsupported NetType query";
708 gethostname(buff,
sizeof(buff));
712 if ((
eMsg = GetAddrs(buff, &myAddrs, aCnt, allIPv64, NoPortRaw)))
713 {
if (eText) *eText =
eMsg;
719 for (
int i = 0; i < aCnt && hasProt != hasIP64; i++)
721 {hasProt =
NetProt(hasProt | hasIPv6);
722 if (!myAddrs[i].isPrivate())
723 hasProt =
NetProt(hasProt | hasPub6);
726 {hasProt =
NetProt(hasProt | hasIPv4);
727 if (!myAddrs[i].isPrivate())
728 hasProt =
NetProt(hasProt | hasPub4);
735 if (hasProt == hasNone && eText) *eText =
"";
744 const char **hName,
const char **hNend,
745 const char **hPort,
const char **hPend)
747 const char *asep = 0;
752 {
if (!(*hNend = index(hSpec+1,
']')))
return false;
753 *hName = hSpec+1; asep = (*hNend)+1;
756 if (!(*hNend = index(hSpec,
':'))) *hNend = hSpec + strlen(hSpec);
762 if (asep && *asep ==
':')
764 while(isalnum(*asep)) asep++;
765 if (*hPort == asep)
return false;
767 }
else *hPort = *hPend = *hNend;
781 SOCKLEN_t slen = (socklen_t)
sizeof(Inet);
784 if ((rc = getsockname(fd, &Inet.
Addr, &slen)))
786 if (eText) setET(eText, errno);
790 return static_cast<int>(ntohs(Inet.
v6.sin6_port));
798 #define IPPROTO_TCP 6
816 if (!getprotobyname_r(pname, &pp, buff,
sizeof(buff)))
819 #elif !defined(HAVE_PROTOR)
821 if (!(pp = getprotobyname(pname))) protoid =
IPPROTO_TCP;
822 else protoid = pp->p_proto;
826 struct protoent *ppp;
827 if (getprotobyname_r(pname, &pp, buff,
sizeof(buff), &ppp))
839 struct addrinfo *rP = 0, myHints;
846 portnum = strtol(sName, &send, 10);
847 if (portnum > 0 && portnum < 65536 && *send == 0)
return portnum;
848 if (eText) *eText =
"invalid port number";
854 memset(&myHints, 0,
sizeof(myHints));
855 myHints.ai_socktype = (isUDP ? SOCK_DGRAM : SOCK_STREAM);
859 rc = getaddrinfo(0, sName, &myHints, &rP);
861 {
if (eText) *eText = (rc ? gai_strerror(rc) :
"service not found");
862 if (rP) freeaddrinfo(rP);
868 portnum = int(ntohs(
SIN_PORT(rP))) & 0x0000ffff;
870 if (!portnum && eText) *eText =
"service has no port";
883 if (aOpts != onlyIPv4 && aOpts != allIPMap)
887 else {autoFamily = AF_UNSPEC; autoHints = AI_V4MAPPED | AI_ADDRCONFIG;
888 return AI_V4MAPPED | AI_ADDRCONFIG;
894 if (aOpts == onlyIPv4)
895 {autoFamily = AF_INET; autoHints = 0;
return 0;}
899 autoFamily = AF_INET6;
900 autoHints = AI_V4MAPPED | AI_ALL;
901 return AI_V4MAPPED | AI_ALL;
908 int XrdNetUtils::setET(
const char **errtxt,
int rc)
911 else *errtxt =
"unexpected error";
926 hList = Hosts(hSpec, 1234, 2, 0, eText);
930 isSingle = !hList || hList->
next == 0;
934 while((hNow = hList))
935 {hList = hList->
next;
946 if (!SetSockBlocking(sockfd,
false, errMsg)) {
951 int result = connect(sockfd, clientAddr, clientAddrLen);
955 if(!SetSockBlocking(sockfd,
true, errMsg)) {
960 }
else if (errno != EINPROGRESS) {
961 errMsg <<
"Connection failed: " << strerror(errno);
968 fds.events = POLLOUT;
970 result = poll(&fds, 1, timeout_sec * 1000);
973 errMsg <<
"Poll error: " << strerror(errno);
976 }
else if (result == 0) {
977 errMsg <<
"Connection timed out";
982 if (!(fds.revents & POLLOUT)) {
984 errMsg <<
"Poll returned without error but the corresponding socket (" << sockfd <<
") is not ready to write";
990 socklen_t len =
sizeof(so_error);
991 getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
993 errMsg <<
"Connection failed after poll: " << strerror(so_error);
998 if(!SetSockBlocking(sockfd,
true, errMsg)) {
1005 bool XrdNetUtils::SetSockBlocking(
int sockfd,
bool blocking, std::stringstream & errMsg) {
1006 int flags =
fcntl(sockfd, F_GETFL, 0);
1008 errMsg <<
"Failed to get socket flags " << strerror(errno);
1012 flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
1014 if (
fcntl(sockfd, F_SETFL, flags) == -1) {
1015 errMsg <<
"Failed to set socket blocking/non-blocking " << strerror(errno);
int fcntl(int fd, int cmd,...)
const char * XrdSysE2T(int errcode)
static const int noPort
Do not add port number.
static const int old6Map4
Use deprecated IPV6 mapped format.
static bool isHostName(const char *name)
static const int noPortRaw
Use raw address format (no port)
static const int prefipv4
Use if mapped IPV4 actual format.
bool isIPType(IPType ipType) const
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtAddr
Address using suitable ipv4 or ipv6 format.
const char * Name(const char *eName=0, const char **eText=0)
static const int PortInSpec
const char * Set(const char *hSpec, int pNum=PortInSpec)
static const int haveIPv4
ifList == 0 && non-local ipv4 i/f found (or'd)
static int GetIF(XrdOucTList **ifList, const char **eText=0)
static const int havePub6
ifList == 0 && public ipv6 i/f found (or'd)
static const int havePub4
ifList == 0 && public ipv4 i/f found (or'd)
static const int haveIPv6
ifList == 0 && non-local ipv6 i/f found (or'd)
static const char * FQN(const char **etext=0)
static const char * GetAddrs(const std::string &hSpec, std::vector< XrdNetAddr > &aVec, int *ordn=0, XrdNetUtils::AddrOpts opts=XrdNetUtils::allIPMap, int pNum=XrdNetUtils::PortInSpec)
static const char pfx
Registry names must start with this character.
static bool Match(const char *hName, const char *pattern)
static char * MyHostName(const char *eName="*unknown*", const char **eText=0)
static int GetSokInfo(int fd, char *theAddr, int theALen, char &theType)
static int Encode(const XrdNetSockAddr *sadr, char *buff, int blen, int port=-1)
static int IPFormat(const struct sockaddr *sAddr, char *bP, int bL, int opts=0)
static bool Singleton(const char *hSpec, const char **eText=0)
static const char * GetAddrs(const char *hSpec, XrdNetAddr *aListP[], int &aListN, AddrOpts opts=allIPMap, int pNum=PortInSpec)
static int Decode(XrdNetSockAddr *sadr, const char *buff, int blen)
static NetProt NetConfig(NetType netquery=qryINET, const char **eText=0)
static bool ConnectWithTimeout(int sockfd, const struct sockaddr *clientAddr, size_t clientAddrLen, uint32_t timeout_sec, std::stringstream &errMsg)
static int Port(int fd, const char **eText=0)
static int ProtoID(const char *pName)
static int ServPort(const char *sName, bool isUDP=false, const char **eText=0)
static XrdOucTList * Hosts(const char *hSpec, int hPort=-1, int hWant=8, int *sPort=0, const char **eText=0)
static bool Parse(const char *hSpec, const char **hName, const char **hNend, const char **hPort, const char **hPend)
static int SetAuto(AddrOpts aOpts=allIPMap)
char ipAdr[MAXHOSTNAMELEN+15]
hpSpec(XrdNetUtils::AddrOpts opts)