37 #include <netinet/in.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
60 int XrdNetUtils::autoFamily;
72 static const int ipv4Sz =
sizeof(
struct in_addr)*2+4;
73 static const int ipv6Sz =
sizeof(
struct in6_addr)*2+4;
74 char bval[
sizeof(
struct in6_addr)+2];
75 int isv6, n, i = 0, Odd = 0;
79 if (blen == ipv6Sz) isv6 = 1;
80 else if (blen == ipv4Sz) isv6 = 0;
86 {
if (*buff >=
'0' && *buff <=
'9') n = *buff-48;
87 else if (*buff >=
'a' && *buff <=
'f') n = *buff-87;
88 else if (*buff >=
'A' && *buff <=
'F') n = *buff-55;
90 if (Odd) bval[i++] |= n;
91 else bval[i ] = n << 4;
102 {sadr->
v6.sin6_family = AF_INET6;
103 memcpy(&(sadr->
v6.sin6_port), bval, 2);
104 memcpy(&(sadr->
v6.sin6_addr), &bval[2],
sizeof(
struct in6_addr));
106 sadr->
v4.sin_family = AF_INET;
107 memcpy(&(sadr->
v4.sin_port), bval, 2);
108 memcpy(&(sadr->
v4.sin_addr), &bval[2],
sizeof(
struct in_addr));
113 return static_cast<int>(ntohs(sadr->
v6.sin6_port));
123 static const char *hv =
"0123456789abcdef";
124 char *src, bval[
sizeof(
struct in6_addr)+2];
129 if (sadr->
Addr.sa_family == AF_INET6)
130 {src = (
char *)&(sadr->
v6.sin6_addr); asz =
sizeof(
struct in6_addr);}
131 else if (sadr->
Addr.sa_family == AF_INET)
132 {src = (
char *)&(sadr->
v4.sin_addr); asz =
sizeof(
struct in_addr); }
134 if (blen < (asz*2)+5)
return -((asz*2)+5);
138 if (port < 0) memcpy(bval, &(sadr->
v6.sin6_port), 2);
139 else {
short sPort = htons(
static_cast<short>(port));
140 memcpy(bval, &sPort, 2);
142 memcpy(&bval[2], src, asz);
147 for (i = 0; i < asz; i++)
148 {buff[j++] = hv[(bval[i] >> 4) & 0x0f];
149 buff[j++] = hv[ bval[i] & 0x0f];
162 #define OrderXX (XrdNetUtils::order46 | XrdNetUtils::order64)
164 #define SIN_PORT(x) ((struct sockaddr_in *)(x->ai_addr))->sin_port
196 int *ordn,
unsigned int rotNum)
198 struct addrinfo *aP, *nP[2];
204 {nP[0] = aInfo.
aiP4; aN[0] = aInfo.
aNum4;
211 for (
int k = 0; k < 2; k++)
213 if (sz && (aP = nP[k]))
214 {
int iBeg = rotNum % sz, iEnd = sz;
215 do {
for (
int i = iBeg; i < iEnd && aP; i++)
216 {
int pNum = int(
SIN_PORT(aP)) & 0x0000ffff;
220 iEnd = iBeg; iBeg = 0;
231 else *ordn = aInfo.
aNum6;
253 GetHints(aInfo,
opts);
257 if ((eText = GetHostPort(aInfo, hSpec, pNum))
258 || (eText = GetAInfo(aInfo)))
return eText;
266 FillAddr(aInfo, *aVec);
277 std::vector<XrdNetAddr> &aVec,
297 GetHints(aInfo,
opts);
301 if ((eText = GetHostPort(aInfo, hSpec.c_str(), pNum))
302 || (eText = GetAInfo(aInfo)))
return eText;
309 FillAddr(aInfo, aVec.data(), ordn);
320 std::vector<XrdNetAddr> &aVec,
int *ordn,
331 if (!hSVec.size())
return 0;
335 GetHints(aInfo,
opts);
339 for (
int i = 0; i < (int)hSVec.size(); i++)
340 {
if (((eText = GetHostPort(aInfo, hSVec[i].c_str(), PortInSpec))
341 || (eText = GetAInfo(aInfo))) && !force)
return eText;
348 FillAddr(aInfo, aVec.data(), ordn, rotNum);
362 struct addrinfo *last4 = 0, *last6 = 0, *xP = 0, *rP = 0, *nP;
363 unsigned short pNum =
static_cast<unsigned short>(aInfo.
port);
367 int rc = getaddrinfo(aInfo.
ipAddr, 0, &aInfo.
hints, &rP);
369 {
if (rP) freeaddrinfo(rP);
370 return (rc ? gai_strerror(rc) :
"host not found");
376 do {nP = rP->ai_next;
377 if (rP->ai_family == AF_INET6 || rP->ai_family == AF_INET)
379 bool v4mapped =
false;
380 if (rP->ai_family == AF_INET6)
381 {
struct sockaddr_in6 *ipv6 = (
struct sockaddr_in6 *)rP->ai_addr;
382 if (IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr))
383 {rP->ai_next = xP; xP = rP;
continue;}
384 v4mapped = IN6_IS_ADDR_V4MAPPED(&ipv6->sin6_addr);
386 if (aInfo.
noOrder || rP->ai_family == AF_INET || v4mapped)
387 {
if (last4) last4->ai_next = rP;
388 else aInfo.
aiP4 = rP;
392 if (last6) last6->ai_next = rP;
393 else aInfo.
aiP6 = rP;
398 }
else {rP->ai_next = xP; xP = rP;}
403 if (xP) freeaddrinfo(xP);
414 struct addrinfo &hints = aInfo.
hints;
418 memset(&hints, 0,
sizeof(hints));
419 hints.ai_socktype = (aInfo.
onlyUDP ? SOCK_DGRAM : SOCK_STREAM);
420 opts =
opts & ~(onlyUDP | order46 | order64);
422 {
case allIPMap: hints.ai_family = AF_INET6;
423 hints.ai_flags = AI_V4MAPPED | AI_ALL;
425 case allIPv64: hints.ai_family = AF_UNSPEC;
427 case allV4Map: hints.ai_family = AF_INET;
430 case onlyIPv6: hints.ai_family = AF_INET6;
432 case onlyIPv4: hints.ai_family = AF_INET;
434 case prefIPv6: hints.ai_family = AF_INET6;
435 hints.ai_flags = AI_V4MAPPED;
437 case prefAuto: hints.ai_family = autoFamily;
438 hints.ai_flags = autoHints;
440 default: hints.ai_family = AF_INET6;
441 hints.ai_flags = AI_V4MAPPED | AI_ALL;
451 const char *hSpec,
int pNum)
453 static const char *badHS =
"invalid host specification";
454 const char *hnBeg, *hnEnd, *pnBeg, *pnEnd;
458 if (!hSpec)
return badHS;
463 if (pNum == NoPortRaw)
464 {hnBeg = aInfo.
ipAdr;
467 if (!Parse(aInfo.
ipAdr, &hnBeg, &hnEnd, &pnBeg, &pnEnd))
return badHS;
470 {
if (pNum == PortInSpec)
return "port not specified";
471 aInfo.
port = abs(pNum);
475 int n = ServPort(pnBeg, aInfo.
onlyUDP, &eText);
476 if (!n)
return eText;
477 if (pNum < 0) aInfo.
port = n;
483 if (aInfo.
hints.ai_family == AF_INET6 && aInfo.
ipAdr[0] !=
'['
485 {memcpy(aInfo.
ipMap,
"::ffff:", 7);
487 }
else aInfo.
ipAddr = hnBeg;
506 unsigned short thePort;
510 rc = (fd > 0 ? getpeername( fd, &theIP.
Addr, &addrSize)
511 : getsockname(-fd, &theIP.
Addr, &addrSize));
512 if (rc)
return -errno;
516 if (ipAddr.
Set(&theIP.
Addr))
return -EAFNOSUPPORT;
525 if (theAddr && theALen > 0
531 thePort = htons((theIP.
Addr.sa_family == AF_INET
532 ? theIP.
v4.sin_port : theIP.
v6.sin6_port));
533 return static_cast<int>(thePort);
542 int *sPort,
const char **eText)
544 static const int hMax = 8;
547 const char *etext, *hName;
553 if (hWant > hMax) hWant = hMax;
554 else if (hWant < 1) hWant = 1;
558 if ((etext = aList[0].Set(hSpec, numIP, hWant, hPort)))
559 {
if (eText) *eText = etext;
566 for (i = 0; i < numIP; i++)
567 {
if (sPort && myAddr.Same(&aList[i]))
568 {*sPort = aList[i].
Port(); sPort = 0;}
569 hName = aList[i].
Name(
"");
570 for (k = 0; k < i; k++) {
if (!strcmp(hName, aList[k].Name(
"")))
break;}
571 if (k >= i) tList =
new XrdOucTList(hName, aList[i].Port(), tList);
576 if (eText) *eText = (tList ? 0 :
"unknown processing error");
585 char *bP,
int bL,
int opts)
592 if (theAddr.
Set(sAddr))
return 0;
610 rc = (fd > 0 ? getpeername( fd, &theIP.
Addr, &addrSize)
611 : getsockname(-fd, &theIP.
Addr, &addrSize));
616 return IPFormat(&theIP.
Addr, bP, bL,
opts);
625 static const int maxIP = 16;
631 if (!strcmp(HostPat, HostName))
return true;
635 if ((mval = index(HostPat, (
int)
'*')))
636 { i = mval - HostPat; mval++;
637 k = strlen(HostName); j = strlen(mval);
639 || strncmp(HostName, HostPat,i)
640 || strncmp((HostName+k-j),mval,j))
return false;
647 if (i && HostPat[i-1] ==
'+')
650 if (i >= (
int)
sizeof(hBuff))
return false;
651 memcpy(hBuff, HostPat, i-1);
653 if (InetAddr[0].Set(hBuff, i, maxIP, 0))
return false;
654 while(i--)
if ((mval = InetAddr[i].Name()) && !strcmp(mval, HostName))
673 if (!fqn) fqn = eName;
674 return (fqn ? strdup(fqn) : 0);
692 if (netquery != qryINET && netquery != qryINIF)
693 {
if (eText) *eText =
"unsupported NetType query";
709 gethostname(buff,
sizeof(buff));
714 if ((
eMsg = GetAddrs(buff, &myAddrs, aCnt, allIPv64, NoPortRaw)))
715 {
if (eText) *eText =
eMsg;
721 for (
int i = 0; i < aCnt && hasProt != hasIP64; i++)
723 {hasProt =
NetProt(hasProt | hasIPv6);
724 if (!myAddrs[i].isPrivate())
725 hasProt =
NetProt(hasProt | hasPub6);
728 {hasProt =
NetProt(hasProt | hasIPv4);
729 if (!myAddrs[i].isPrivate())
730 hasProt =
NetProt(hasProt | hasPub4);
737 if (hasProt == hasNone && eText) *eText =
"";
746 const char **hName,
const char **hNend,
747 const char **hPort,
const char **hPend)
749 const char *asep = 0;
754 {
if (!(*hNend = index(hSpec+1,
']')))
return false;
755 *hName = hSpec+1; asep = (*hNend)+1;
758 if (!(*hNend = index(hSpec,
':'))) *hNend = hSpec + strlen(hSpec);
764 if (asep && *asep ==
':')
766 while(isalnum(*asep)) asep++;
767 if (*hPort == asep)
return false;
769 }
else *hPort = *hPend = *hNend;
783 SOCKLEN_t slen = (socklen_t)
sizeof(Inet);
786 if ((rc = getsockname(fd, &Inet.
Addr, &slen)))
788 if (eText) setET(eText, errno);
792 return static_cast<int>(ntohs(Inet.
v6.sin6_port));
800 #define IPPROTO_TCP 6
818 if (!getprotobyname_r(pname, &pp, buff,
sizeof(buff)))
821 #elif !defined(HAVE_PROTOR)
823 if (!(pp = getprotobyname(pname))) protoid =
IPPROTO_TCP;
824 else protoid = pp->p_proto;
828 struct protoent *ppp;
829 if (getprotobyname_r(pname, &pp, buff,
sizeof(buff), &ppp))
841 struct addrinfo *rP = 0, myHints;
848 portnum = strtol(sName, &send, 10);
849 if (portnum > 0 && portnum < 65536 && *send == 0)
return portnum;
850 if (eText) *eText =
"invalid port number";
856 memset(&myHints, 0,
sizeof(myHints));
857 myHints.ai_socktype = (isUDP ? SOCK_DGRAM : SOCK_STREAM);
861 rc = getaddrinfo(0, sName, &myHints, &rP);
863 {
if (eText) *eText = (rc ? gai_strerror(rc) :
"service not found");
864 if (rP) freeaddrinfo(rP);
870 portnum = int(ntohs(
SIN_PORT(rP))) & 0x0000ffff;
872 if (!portnum && eText) *eText =
"service has no port";
885 if (aOpts != onlyIPv4 && aOpts != allIPMap)
889 else {autoFamily = AF_UNSPEC; autoHints = AI_V4MAPPED | AI_ADDRCONFIG;
890 return AI_V4MAPPED | AI_ADDRCONFIG;
896 if (aOpts == onlyIPv4)
897 {autoFamily = AF_INET; autoHints = 0;
return 0;}
901 autoFamily = AF_INET6;
902 autoHints = AI_V4MAPPED | AI_ALL;
903 return AI_V4MAPPED | AI_ALL;
910 int XrdNetUtils::setET(
const char **errtxt,
int rc)
913 else *errtxt =
"unexpected error";
928 hList = Hosts(hSpec, 1234, 2, 0, eText);
932 isSingle = !hList || hList->
next == 0;
936 while((hNow = hList))
937 {hList = hList->
next;
948 if (!SetSockBlocking(sockfd,
false, errMsg)) {
953 int result = connect(sockfd, clientAddr, clientAddrLen);
957 if(!SetSockBlocking(sockfd,
true, errMsg)) {
962 }
else if (errno != EINPROGRESS) {
963 errMsg <<
"Connection failed: " << strerror(errno);
970 fds.events = POLLOUT;
972 result = poll(&fds, 1, timeout_sec * 1000);
975 errMsg <<
"Poll error: " << strerror(errno);
978 }
else if (result == 0) {
979 errMsg <<
"Connection timed out";
984 if (!(fds.revents & POLLOUT)) {
986 errMsg <<
"Poll returned without error but the corresponding socket (" << sockfd <<
") is not ready to write";
992 socklen_t len =
sizeof(so_error);
993 getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
995 errMsg <<
"Connection failed after poll: " << strerror(so_error);
1000 if(!SetSockBlocking(sockfd,
true, errMsg)) {
1007 bool XrdNetUtils::SetSockBlocking(
int sockfd,
bool blocking, std::stringstream & errMsg) {
1008 int flags =
fcntl(sockfd, F_GETFL, 0);
1010 errMsg <<
"Failed to get socket flags " << strerror(errno);
1014 flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
1016 if (
fcntl(sockfd, F_SETFL, flags) == -1) {
1017 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)
static void toLower(char *str)
char ipAdr[MAXHOSTNAMELEN+15]
hpSpec(XrdNetUtils::AddrOpts opts)