37 #include <netinet/in.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
60 int XrdNetUtils::autoFamily;
80 if (ip1.
Addr.sa_family == AF_INET6)
81 {
if (memcmp(&ip1.
v6.sin6_addr,&ip2.
v6.sin6_addr,
sizeof(
struct in6_addr)))
83 if (psame) *psame = (ip1.
v6.sin6_port == ip2.
v6.sin6_port);
89 if (ip1.
Addr.sa_family == AF_INET)
90 {
if (memcmp(&ip1.
v4.sin_addr,&ip2.
v4.sin_addr,
sizeof(
struct in_addr)))
92 if (psame) *psame = (ip1.
v4.sin_port == ip2.
v4.sin_port);
107 static const int ipv4Sz =
sizeof(
struct in_addr)*2+4;
108 static const int ipv6Sz =
sizeof(
struct in6_addr)*2+4;
109 char bval[
sizeof(
struct in6_addr)+2];
110 int isv6, n, i = 0, Odd = 0;
114 if (blen == ipv6Sz) isv6 = 1;
115 else if (blen == ipv4Sz) isv6 = 0;
121 {
if (*buff >=
'0' && *buff <=
'9') n = *buff-48;
122 else if (*buff >=
'a' && *buff <=
'f') n = *buff-87;
123 else if (*buff >=
'A' && *buff <=
'F') n = *buff-55;
125 if (Odd) bval[i++] |= n;
126 else bval[i ] = n << 4;
137 {sadr->
v6.sin6_family = AF_INET6;
138 memcpy(&(sadr->
v6.sin6_port), bval, 2);
139 memcpy(&(sadr->
v6.sin6_addr), &bval[2],
sizeof(
struct in6_addr));
141 sadr->
v4.sin_family = AF_INET;
142 memcpy(&(sadr->
v4.sin_port), bval, 2);
143 memcpy(&(sadr->
v4.sin_addr), &bval[2],
sizeof(
struct in_addr));
148 return static_cast<int>(ntohs(sadr->
v6.sin6_port));
158 static const char *hv =
"0123456789abcdef";
159 char *src, bval[
sizeof(
struct in6_addr)+2];
164 if (sadr->
Addr.sa_family == AF_INET6)
165 {src = (
char *)&(sadr->
v6.sin6_addr); asz =
sizeof(
struct in6_addr);}
166 else if (sadr->
Addr.sa_family == AF_INET)
167 {src = (
char *)&(sadr->
v4.sin_addr); asz =
sizeof(
struct in_addr); }
169 if (blen < (asz*2)+5)
return -((asz*2)+5);
173 if (port < 0) memcpy(bval, &(sadr->
v6.sin6_port), 2);
174 else {
short sPort = htons(
static_cast<short>(port));
175 memcpy(bval, &sPort, 2);
177 memcpy(&bval[2], src, asz);
182 for (i = 0; i < asz; i++)
183 {buff[j++] = hv[(bval[i] >> 4) & 0x0f];
184 buff[j++] = hv[ bval[i] & 0x0f];
197 #define OrderXX (XrdNetUtils::order46 | XrdNetUtils::order64)
199 #define SIN_PORT(x) ((struct sockaddr_in *)(x->ai_addr))->sin_port
231 int *ordn,
unsigned int rotNum)
233 struct addrinfo *aP, *nP[2];
239 {nP[0] = aInfo.
aiP4; aN[0] = aInfo.
aNum4;
246 for (
int k = 0; k < 2; k++)
248 if (sz && (aP = nP[k]))
249 {
int iBeg = rotNum % sz, iEnd = sz;
250 do {
for (
int i = iBeg; i < iEnd && aP; i++)
251 {
int pNum = int(
SIN_PORT(aP)) & 0x0000ffff;
255 iEnd = iBeg; iBeg = 0;
266 else *ordn = aInfo.
aNum6;
288 GetHints(aInfo,
opts);
292 if ((eText = GetHostPort(aInfo, hSpec, pNum))
293 || (eText = GetAInfo(aInfo)))
return eText;
301 FillAddr(aInfo, *aVec);
312 std::vector<XrdNetAddr> &aVec,
332 GetHints(aInfo,
opts);
336 if ((eText = GetHostPort(aInfo, hSpec.c_str(), pNum))
337 || (eText = GetAInfo(aInfo)))
return eText;
344 FillAddr(aInfo, aVec.data(), ordn);
355 std::vector<XrdNetAddr> &aVec,
int *ordn,
366 if (!hSVec.size())
return 0;
370 GetHints(aInfo,
opts);
374 for (
int i = 0; i < (int)hSVec.size(); i++)
375 {
if (((eText = GetHostPort(aInfo, hSVec[i].c_str(), PortInSpec))
376 || (eText = GetAInfo(aInfo))) && !force)
return eText;
383 FillAddr(aInfo, aVec.data(), ordn, rotNum);
397 struct addrinfo *last4 = 0, *last6 = 0, *xP = 0, *rP = 0, *nP;
398 unsigned short pNum =
static_cast<unsigned short>(aInfo.
port);
402 int rc = getaddrinfo(aInfo.
ipAddr, 0, &aInfo.
hints, &rP);
404 {
if (rP) freeaddrinfo(rP);
405 return (rc ? gai_strerror(rc) :
"host not found");
411 do {nP = rP->ai_next;
412 if (rP->ai_family == AF_INET6 || rP->ai_family == AF_INET)
414 bool v4mapped =
false;
415 if (rP->ai_family == AF_INET6)
416 {
struct sockaddr_in6 *ipv6 = (
struct sockaddr_in6 *)rP->ai_addr;
417 if (IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr))
418 {rP->ai_next = xP; xP = rP;
continue;}
419 v4mapped = IN6_IS_ADDR_V4MAPPED(&ipv6->sin6_addr);
421 if (aInfo.
noOrder || rP->ai_family == AF_INET || v4mapped)
422 {
if (last4) last4->ai_next = rP;
423 else aInfo.
aiP4 = rP;
427 if (last6) last6->ai_next = rP;
428 else aInfo.
aiP6 = rP;
433 }
else {rP->ai_next = xP; xP = rP;}
438 if (xP) freeaddrinfo(xP);
449 struct addrinfo &hints = aInfo.
hints;
453 memset(&hints, 0,
sizeof(hints));
454 hints.ai_socktype = (aInfo.
onlyUDP ? SOCK_DGRAM : SOCK_STREAM);
455 opts =
opts & ~(onlyUDP | order46 | order64);
457 {
case allIPMap: hints.ai_family = AF_INET6;
458 hints.ai_flags = AI_V4MAPPED | AI_ALL;
460 case allIPv64: hints.ai_family = AF_UNSPEC;
462 case allV4Map: hints.ai_family = AF_INET;
465 case onlyIPv6: hints.ai_family = AF_INET6;
467 case onlyIPv4: hints.ai_family = AF_INET;
469 case prefIPv6: hints.ai_family = AF_INET6;
470 hints.ai_flags = AI_V4MAPPED;
472 case prefAuto: hints.ai_family = autoFamily;
473 hints.ai_flags = autoHints;
475 default: hints.ai_family = AF_INET6;
476 hints.ai_flags = AI_V4MAPPED | AI_ALL;
486 const char *hSpec,
int pNum)
488 static const char *badHS =
"invalid host specification";
489 const char *hnBeg, *hnEnd, *pnBeg, *pnEnd;
493 if (!hSpec)
return badHS;
498 if (pNum == NoPortRaw)
499 {hnBeg = aInfo.
ipAdr;
502 if (!Parse(aInfo.
ipAdr, &hnBeg, &hnEnd, &pnBeg, &pnEnd))
return badHS;
505 {
if (pNum == PortInSpec)
return "port not specified";
506 aInfo.
port = abs(pNum);
510 int n = ServPort(pnBeg, aInfo.
onlyUDP, &eText);
511 if (!n)
return eText;
512 if (pNum < 0) aInfo.
port = n;
518 if (aInfo.
hints.ai_family == AF_INET6 && aInfo.
ipAdr[0] !=
'['
520 {memcpy(aInfo.
ipMap,
"::ffff:", 7);
522 }
else aInfo.
ipAddr = hnBeg;
541 unsigned short thePort;
545 rc = (fd > 0 ? getpeername( fd, &theIP.
Addr, &addrSize)
546 : getsockname(-fd, &theIP.
Addr, &addrSize));
547 if (rc)
return -errno;
551 if (ipAddr.
Set(&theIP.
Addr))
return -EAFNOSUPPORT;
560 if (theAddr && theALen > 0
566 thePort = htons((theIP.
Addr.sa_family == AF_INET
567 ? theIP.
v4.sin_port : theIP.
v6.sin6_port));
568 return static_cast<int>(thePort);
577 int *sPort,
const char **eText)
579 static const int hMax = 8;
582 const char *etext, *hName;
588 if (hWant > hMax) hWant = hMax;
589 else if (hWant < 1) hWant = 1;
593 if ((etext = aList[0].Set(hSpec, numIP, hWant, hPort)))
594 {
if (eText) *eText = etext;
601 for (i = 0; i < numIP; i++)
602 {
if (sPort && myAddr.Same(&aList[i]))
603 {*sPort = aList[i].
Port(); sPort = 0;}
604 hName = aList[i].
Name(
"");
605 for (k = 0; k < i; k++) {
if (!strcmp(hName, aList[k].Name(
"")))
break;}
606 if (k >= i) tList =
new XrdOucTList(hName, aList[i].Port(), tList);
611 if (eText) *eText = (tList ? 0 :
"unknown processing error");
620 char *bP,
int bL,
int opts)
627 if (theAddr.
Set(sAddr))
return 0;
645 rc = (fd > 0 ? getpeername( fd, &theIP.
Addr, &addrSize)
646 : getsockname(-fd, &theIP.
Addr, &addrSize));
651 return IPFormat(&theIP.
Addr, bP, bL,
opts);
660 static const int maxIP = 16;
666 if (!strcmp(HostPat, HostName))
return true;
670 if ((mval = index(HostPat, (
int)
'*')))
671 { i = mval - HostPat; mval++;
672 k = strlen(HostName); j = strlen(mval);
674 || strncmp(HostName, HostPat,i)
675 || strncmp((HostName+k-j),mval,j))
return false;
682 if (i && HostPat[i-1] ==
'+')
685 if (i >= (
int)
sizeof(hBuff))
return false;
686 memcpy(hBuff, HostPat, i-1);
688 if (InetAddr[0].Set(hBuff, i, maxIP, 0))
return false;
689 while(i--)
if ((mval = InetAddr[i].Name()) && !strcmp(mval, HostName))
708 if (!fqn) fqn = eName;
709 return (fqn ? strdup(fqn) : 0);
727 if (netquery != qryINET && netquery != qryINIF)
728 {
if (eText) *eText =
"unsupported NetType query";
744 gethostname(buff,
sizeof(buff));
749 if ((
eMsg = GetAddrs(buff, &myAddrs, aCnt, allIPv64, NoPortRaw)))
750 {
if (eText) *eText =
eMsg;
756 for (
int i = 0; i < aCnt && hasProt != hasIP64; i++)
758 {hasProt =
NetProt(hasProt | hasIPv6);
759 if (!myAddrs[i].isPrivate())
760 hasProt =
NetProt(hasProt | hasPub6);
763 {hasProt =
NetProt(hasProt | hasIPv4);
764 if (!myAddrs[i].isPrivate())
765 hasProt =
NetProt(hasProt | hasPub4);
772 if (hasProt == hasNone && eText) *eText =
"";
781 const char **hName,
const char **hNend,
782 const char **hPort,
const char **hPend)
784 const char *asep = 0;
789 {
if (!(*hNend = index(hSpec+1,
']')))
return false;
790 *hName = hSpec+1; asep = (*hNend)+1;
793 if (!(*hNend = index(hSpec,
':'))) *hNend = hSpec + strlen(hSpec);
799 if (asep && *asep ==
':')
801 while(isalnum(*asep)) asep++;
802 if (*hPort == asep)
return false;
804 }
else *hPort = *hPend = *hNend;
818 SOCKLEN_t slen = (socklen_t)
sizeof(Inet);
821 if ((rc = getsockname(fd, &Inet.
Addr, &slen)))
823 if (eText) setET(eText, errno);
827 return static_cast<int>(ntohs(Inet.
v6.sin6_port));
835 #define IPPROTO_TCP 6
853 if (!getprotobyname_r(pname, &pp, buff,
sizeof(buff)))
856 #elif !defined(HAVE_PROTOR)
858 if (!(pp = getprotobyname(pname))) protoid =
IPPROTO_TCP;
859 else protoid = pp->p_proto;
863 struct protoent *ppp;
864 if (getprotobyname_r(pname, &pp, buff,
sizeof(buff), &ppp))
876 struct addrinfo *rP = 0, myHints;
883 portnum = strtol(sName, &send, 10);
884 if (portnum > 0 && portnum < 65536 && *send == 0)
return portnum;
885 if (eText) *eText =
"invalid port number";
891 memset(&myHints, 0,
sizeof(myHints));
892 myHints.ai_socktype = (isUDP ? SOCK_DGRAM : SOCK_STREAM);
896 rc = getaddrinfo(0, sName, &myHints, &rP);
898 {
if (eText) *eText = (rc ? gai_strerror(rc) :
"service not found");
899 if (rP) freeaddrinfo(rP);
905 portnum = int(ntohs(
SIN_PORT(rP))) & 0x0000ffff;
907 if (!portnum && eText) *eText =
"service has no port";
920 if (aOpts != onlyIPv4 && aOpts != allIPMap)
924 else {autoFamily = AF_UNSPEC; autoHints = AI_V4MAPPED | AI_ADDRCONFIG;
925 return AI_V4MAPPED | AI_ADDRCONFIG;
931 if (aOpts == onlyIPv4)
932 {autoFamily = AF_INET; autoHints = 0;
return 0;}
936 autoFamily = AF_INET6;
937 autoHints = AI_V4MAPPED | AI_ALL;
938 return AI_V4MAPPED | AI_ALL;
945 int XrdNetUtils::setET(
const char **errtxt,
int rc)
948 else *errtxt =
"unexpected error";
963 hList = Hosts(hSpec, 1234, 2, 0, eText);
967 isSingle = !hList || hList->
next == 0;
971 while((hNow = hList))
972 {hList = hList->
next;
983 if (!SetSockBlocking(sockfd,
false, errMsg)) {
988 int result = connect(sockfd, clientAddr, clientAddrLen);
992 if(!SetSockBlocking(sockfd,
true, errMsg)) {
997 }
else if (errno != EINPROGRESS) {
998 errMsg <<
"Connection failed: " << strerror(errno);
1005 fds.events = POLLOUT;
1007 result = poll(&fds, 1, timeout_sec * 1000);
1010 errMsg <<
"Poll error: " << strerror(errno);
1013 }
else if (result == 0) {
1014 errMsg <<
"Connection timed out";
1019 if (!(fds.revents & POLLOUT)) {
1021 errMsg <<
"Poll returned without error but the corresponding socket (" << sockfd <<
") is not ready to write";
1027 socklen_t len =
sizeof(so_error);
1028 getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
1029 if (so_error != 0) {
1030 errMsg <<
"Connection failed after poll: " << strerror(so_error);
1035 if(!SetSockBlocking(sockfd,
true, errMsg)) {
1042 bool XrdNetUtils::SetSockBlocking(
int sockfd,
bool blocking, std::stringstream & errMsg) {
1043 int flags = fcntl(sockfd, F_GETFL, 0);
1045 errMsg <<
"Failed to get socket flags " << strerror(errno);
1049 flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
1051 if (fcntl(sockfd, F_SETFL, flags) == -1) {
1052 errMsg <<
"Failed to set socket blocking/non-blocking " << strerror(errno);
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 IPComp Compare(XrdNetSockAddr &ip1, XrdNetSockAddr &ip2, bool *psame=0)
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)
hpSpec(XrdNetUtils::AddrOpts opts)