XRootD
XrdNetUtils.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d N e t U t i l s . c c */
4 /* */
5 /* (c) 2025 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <cctype>
32 #include <cinttypes>
33 #include <netdb.h>
34 #include <cstring>
35 #include <unistd.h>
36 
37 #include <netinet/in.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
40 #include <fcntl.h>
41 #include <poll.h>
42 
43 #include "XrdNet/XrdNetAddr.hh"
44 #include "XrdNet/XrdNetIdentity.hh"
45 #include "XrdNet/XrdNetIF.hh"
46 #include "XrdNet/XrdNetRegistry.hh"
47 #include "XrdNet/XrdNetUtils.hh"
48 #include "XrdOuc/XrdOucTList.hh"
49 #include "XrdOuc/XrdOucUtils.hh"
50 #include "XrdSys/XrdSysE2T.hh"
51 #include "XrdSys/XrdSysPlatform.hh"
52 #ifndef HAVE_PROTOR
53 #include "XrdSys/XrdSysPthread.hh"
54 #endif
55 
56 /******************************************************************************/
57 /* S t a t i c M e m b e r s */
58 /******************************************************************************/
59 
60 int XrdNetUtils::autoFamily;
61 
62 // The following also sets autoFamily!
63 //
64 int XrdNetUtils::autoHints = XrdNetUtils::SetAuto(XrdNetUtils::prefAuto);
65 
66 /******************************************************************************/
67 /* C o m p a r e */
68 /******************************************************************************/
69 
71  XrdNetSockAddr& ip2, bool* psame)
72 {
73 // The family code is always in the same place so trivially check equivalence
74 //
75  if (ip1.Addr.sa_family != ip2.Addr.sa_family) return IPDFam;
76 
77 // Since the mailies are te same we need to check if he actual ip addess is
78 // same, What we check depends on the address family. Start with IPv6.
79 //
80  if (ip1.Addr.sa_family == AF_INET6)
81  {if (memcmp(&ip1.v6.sin6_addr,&ip2.v6.sin6_addr,sizeof(struct in6_addr)))
82  return IPDiff;
83  if (psame) *psame = (ip1.v6.sin6_port == ip2.v6.sin6_port);
84  return IPSame;
85  }
86 
87 // Try IPv4
88 //
89  if (ip1.Addr.sa_family == AF_INET)
90  {if (memcmp(&ip1.v4.sin_addr,&ip2.v4.sin_addr, sizeof(struct in_addr)))
91  return IPDiff;
92  if (psame) *psame = (ip1.v4.sin_port == ip2.v4.sin_port);
93  return IPSame;
94  }
95 
96 // We don't support the address family
97 //
98  return IPNSup;
99 }
100 
101 /******************************************************************************/
102 /* D e c o d e */
103 /******************************************************************************/
104 
105 int XrdNetUtils::Decode(XrdNetSockAddr *sadr, const char *buff, int blen)
106 {
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;
111 
112 // Determine if this will be IPV4 or IPV6 (only ones allowed)
113 //
114  if (blen == ipv6Sz) isv6 = 1;
115  else if (blen == ipv4Sz) isv6 = 0;
116  else return -1;
117 
118 // Convert the whole string to a temporary
119 //
120  while(blen--)
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;
124  else return -1;
125  if (Odd) bval[i++] |= n;
126  else bval[i ] = n << 4;
127  buff++; Odd = ~Odd;
128  }
129 
130 // Clear the address
131 //
132  memset(sadr, 0, sizeof(XrdNetSockAddr));
133 
134 // Copy out the data, as needed
135 //
136  if (isv6)
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));
140  } else {
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));
144  }
145 
146 // Return the converted port (it's the same for v4/v6)
147 //
148  return static_cast<int>(ntohs(sadr->v6.sin6_port));
149 }
150 
151 /******************************************************************************/
152 /* E n c o d e */
153 /******************************************************************************/
154 
155 int XrdNetUtils::Encode(const XrdNetSockAddr *sadr, char *buff, int blen,
156  int port)
157 {
158  static const char *hv = "0123456789abcdef";
159  char *src, bval[sizeof(struct in6_addr)+2];
160  int asz, i, j = 0;
161 
162 // Compute the size we need for the buffer (note we only support IP4/6)
163 //
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); }
168  else return 0;
169  if (blen < (asz*2)+5) return -((asz*2)+5);
170 
171 // Get the port value in the first two bytes followed by the address.
172 //
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);
176  }
177  memcpy(&bval[2], src, asz);
178  asz += 2;
179 
180 // Now convert to hex
181 //
182  for (i = 0; i < asz; i++)
183  {buff[j++] = hv[(bval[i] >> 4) & 0x0f];
184  buff[j++] = hv[ bval[i] & 0x0f];
185  }
186  buff[j] = '\0';
187 
188 // All done
189 //
190  return asz*2;
191 }
192 
193 /******************************************************************************/
194 /* Private: F i l l A d d r s */
195 /******************************************************************************/
196 
197 #define OrderXX (XrdNetUtils::order46 | XrdNetUtils::order64)
198 
199 #define SIN_PORT(x) ((struct sockaddr_in *)(x->ai_addr))->sin_port
200 namespace XrdNetSpace
201 {
202 struct hpSpec
203  {const char *ipAddr;
204  addrinfo hints;
205  addrinfo *aiP4;
206  int aNum4;
207  int aNum6;
208  addrinfo *aiP6;
209  int port;
210  bool map426;
211  bool noOrder;
212  bool order46;
213  bool onlyUDP;
214  char ipMap[7]; // ::ffff: (length = 7)
215  char ipAdr[256];
216 
218  : aiP4(0), aNum4(0), aNum6(0), aiP6(0), map426(false),
219  noOrder((opts & OrderXX) == 0),
220  order46((opts & XrdNetUtils::order46) != 0),
221  onlyUDP((opts & XrdNetUtils::onlyUDP) != 0) {}
222 
223  ~hpSpec() {if (aiP4) freeaddrinfo(aiP4);
224  if (aiP6) freeaddrinfo(aiP6);
225  }
226  };
227 }
228 using namespace XrdNetSpace;
229 
230 void XrdNetUtils::FillAddr(XrdNetSpace::hpSpec &aInfo, XrdNetAddr *aVec,
231  int *ordn, unsigned int rotNum)
232 {
233  struct addrinfo *aP, *nP[2];
234  int aN[2];
235 
236 // Establish ordering
237 //
238  if (aInfo.order46)
239  {nP[0] = aInfo.aiP4; aN[0] = aInfo.aNum4;
240  nP[1] = aInfo.aiP6; aN[1] = aInfo.aNum6;
241  } else {
242  nP[0] = aInfo.aiP6; aN[0] = aInfo.aNum6;
243  nP[1] = aInfo.aiP4; aN[1] = aInfo.aNum4;
244  }
245 
246  for (int k = 0; k < 2; k++)
247  {int sz = aN[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;
252  aVec[i].Set(aP, pNum, aInfo.map426);
253  aP = aP->ai_next;
254  }
255  iEnd = iBeg; iBeg = 0;
256  } while(aP);
257  aVec = &aVec[sz];
258  }
259  }
260 
261 // Supply the ordinal if it is wanted
262 //
263  if (ordn)
264  {if (aInfo.noOrder) *ordn = aInfo.aNum4 + aInfo.aNum6;
265  else if (aInfo.order46) *ordn = aInfo.aNum4;
266  else *ordn = aInfo.aNum6;
267  }
268 }
269 
270 /******************************************************************************/
271 /* G e t A d d r s */
272 /******************************************************************************/
273 
274 const char *XrdNetUtils::GetAddrs(const char *hSpec,
275  XrdNetAddr *aVec[], int &aVsz,
276  XrdNetUtils::AddrOpts opts, int pNum)
277 {
278  const char *eText;
279  hpSpec aInfo(opts);
280 
281 // Prep the returned fields
282 //
283  *aVec = 0;
284  aVsz = 0;
285 
286 // Parse the options
287 //
288  GetHints(aInfo, opts);
289 
290 // Parse the host specification and get addresses
291 //
292  if ((eText = GetHostPort(aInfo, hSpec, pNum))
293  || (eText = GetAInfo(aInfo))) return eText;
294 
295 // If we have any addresses, resize the vector with that many netaddr objects
296 // and then initialze each one of them.
297 //
298  if (aInfo.aNum4 || aInfo.aNum6)
299  {aVsz = aInfo.aNum4 + aInfo.aNum6;
300  *aVec = new XrdNetAddr[(unsigned int)aVsz];
301  FillAddr(aInfo, *aVec);
302  }
303 
304 // All done
305 //
306  return 0;
307 }
308 
309 /******************************************************************************/
310 
311 const char *XrdNetUtils::GetAddrs(const std::string &hSpec,
312  std::vector<XrdNetAddr> &aVec,
313  int *ordn, AddrOpts opts, int pNum)
314 {
315 // If this references a registered name, process it as such.
316 //
317  if (*(hSpec.c_str()) == XrdNetRegistry::pfx)
318  return XrdNetRegistry::GetAddrs(hSpec, aVec, ordn, opts, pNum);
319 
320 // Start up!
321 //
322  const char *eText;
323  hpSpec aInfo(opts);
324 
325 // Clear the result vector
326 //
327  aVec.clear();
328  if (ordn) *ordn = 0;
329 
330 // Parse the options
331 //
332  GetHints(aInfo, opts);
333 
334 // Parse the host specification and get address info
335 //
336  if ((eText = GetHostPort(aInfo, hSpec.c_str(), pNum))
337  || (eText = GetAInfo(aInfo))) return eText;
338 
339 // If we have any addresses, resize the vector with that many netaddr objects
340 // and then initialze each one of them.
341 //
342  if (aInfo.aNum4 || aInfo.aNum6)
343  {aVec.resize(aInfo.aNum4 + aInfo.aNum6);
344  FillAddr(aInfo, aVec.data(), ordn);
345  }
346 
347 // All done
348 //
349  return 0;
350 }
351 
352 /******************************************************************************/
353 
354 const char *XrdNetUtils::GetAddrs(std::vector<std::string> &hSVec,
355  std::vector<XrdNetAddr> &aVec, int *ordn,
356  AddrOpts opts, unsigned int rotNum,
357  bool force)
358 {
359  const char *eText;
360  hpSpec aInfo(opts);
361 
362 // Clear the result vector and make sure we have something to do
363 //
364  aVec.clear();
365  if (ordn) *ordn = 0;
366  if (!hSVec.size()) return 0;
367 
368 // Parse the options
369 //
370  GetHints(aInfo, opts);
371 
372 // Process each specification
373 //
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;
377  }
378 
379 // Size the vector and fill it in
380 //
381  if (aInfo.aNum4 || aInfo.aNum6)
382  {aVec.resize(aInfo.aNum4 + aInfo.aNum6);
383  FillAddr(aInfo, aVec.data(), ordn, rotNum);
384  }
385 
386 // All done
387 //
388  return 0;
389 }
390 
391 /******************************************************************************/
392 /* Private: G e t A I n f o */
393 /******************************************************************************/
394 
395 const char *XrdNetUtils::GetAInfo(XrdNetSpace::hpSpec &aInfo)
396 {
397  struct addrinfo *last4 = 0, *last6 = 0, *xP = 0, *rP = 0, *nP;
398  unsigned short pNum = static_cast<unsigned short>(aInfo.port);
399 
400 // Get all of the addresses
401 //
402  int rc = getaddrinfo(aInfo.ipAddr, 0, &aInfo.hints, &rP);
403  if (rc || !rP)
404  {if (rP) freeaddrinfo(rP);
405  return (rc ? gai_strerror(rc) : "host not found");
406  }
407 
408 // Count the number of entries we will return and chain the entries. We will
409 // never return link local addresses which may be returned (shouldn't but does)
410 //
411  do {nP = rP->ai_next;
412  if (rP->ai_family == AF_INET6 || rP->ai_family == AF_INET)
413  {SIN_PORT(rP) = pNum;
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);
420  }
421  if (aInfo.noOrder || rP->ai_family == AF_INET || v4mapped)
422  {if (last4) last4->ai_next = rP;
423  else aInfo.aiP4 = rP;
424  last4 = rP;
425  aInfo.aNum4++;
426  } else {
427  if (last6) last6->ai_next = rP;
428  else aInfo.aiP6 = rP;
429  last6 = rP;
430  aInfo.aNum6++;
431  }
432  rP->ai_next = 0;
433  } else {rP->ai_next = xP; xP = rP;}
434  } while((rP = nP));
435 
436 // Free any entries that we were not interested in and return
437 //
438  if (xP) freeaddrinfo(xP);
439  return 0;
440 }
441 
442 /******************************************************************************/
443 /* Private: G e t H i n t s */
444 /******************************************************************************/
445 
446 void XrdNetUtils::GetHints(XrdNetSpace::hpSpec &aInfo,
448 {
449  struct addrinfo &hints = aInfo.hints;
450 
451 // Setup the hints
452 //
453  memset(&hints, 0, sizeof(hints));
454  hints.ai_socktype = (aInfo.onlyUDP ? SOCK_DGRAM : SOCK_STREAM);
455  opts = opts & ~(onlyUDP | order46 | order64);
456  switch(opts)
457  {case allIPMap: hints.ai_family = AF_INET6;
458  hints.ai_flags = AI_V4MAPPED | AI_ALL;
459  break;
460  case allIPv64: hints.ai_family = AF_UNSPEC;
461  break;
462  case allV4Map: hints.ai_family = AF_INET;
463  aInfo.map426 = true;
464  break;
465  case onlyIPv6: hints.ai_family = AF_INET6;
466  break;
467  case onlyIPv4: hints.ai_family = AF_INET;
468  break;
469  case prefIPv6: hints.ai_family = AF_INET6;
470  hints.ai_flags = AI_V4MAPPED;
471  break;
472  case prefAuto: hints.ai_family = autoFamily;
473  hints.ai_flags = autoHints;
474  break;
475  default: hints.ai_family = AF_INET6;
476  hints.ai_flags = AI_V4MAPPED | AI_ALL;
477  break;
478  }
479 }
480 
481 /******************************************************************************/
482 /* Private: G e t H o s t P o r t */
483 /******************************************************************************/
484 
485 const char *XrdNetUtils::GetHostPort(XrdNetSpace::hpSpec &aInfo,
486  const char *hSpec, int pNum)
487 {
488  static const char *badHS = "invalid host specification";
489  const char *hnBeg, *hnEnd, *pnBeg, *pnEnd;
490 
491 // Copy the host specification
492 //
493  if (!hSpec) return badHS;
494  strlcpy(aInfo.ipAdr, hSpec, sizeof(aInfo.ipAdr));
495 
496 // Parse the host specification
497 //
498  if (pNum == NoPortRaw)
499  {hnBeg = aInfo.ipAdr;
500  aInfo.port = 0;
501  } else {
502  if (!Parse(aInfo.ipAdr, &hnBeg, &hnEnd, &pnBeg, &pnEnd)) return badHS;
503  aInfo.ipAdr[hnEnd-aInfo.ipAdr] = 0;
504  if (pnBeg == hnEnd)
505  {if (pNum == PortInSpec) return "port not specified";
506  aInfo.port = abs(pNum);
507  } else {
508  const char *eText;
509  aInfo.ipAdr[pnEnd-aInfo.ipAdr] = 0;
510  int n = ServPort(pnBeg, aInfo.onlyUDP, &eText);
511  if (!n) return eText;
512  if (pNum < 0) aInfo.port = n;
513  }
514  }
515 
516 // Check if we need to convert an ipv4 address to an ipv6 one
517 //
518  if (aInfo.hints.ai_family == AF_INET6 && aInfo.ipAdr[0] != '['
520  {memcpy(aInfo.ipMap, "::ffff:", 7);
521  aInfo.ipAddr = aInfo.ipMap;
522  } else aInfo.ipAddr = hnBeg;
523 
524 // All done
525 //
526  return 0;
527 }
528 
529 /******************************************************************************/
530 /* g e t S o k I n f o */
531 /******************************************************************************/
532 
533 int XrdNetUtils::GetSokInfo(int fd, char *theAddr, int theALen, char &theType)
534 {
535  XrdNetSockAddr theIP;
536  XrdNetAddr ipAddr;
537  static const int fmtopts = XrdNetAddrInfo::noPortRaw
539  SOCKLEN_t addrSize = sizeof(theIP);
540  int rc;
541  unsigned short thePort;
542 
543 // The the address wanted
544 //
545  rc = (fd > 0 ? getpeername( fd, &theIP.Addr, &addrSize)
546  : getsockname(-fd, &theIP.Addr, &addrSize));
547  if (rc) return -errno;
548 
549 // Set the address
550 //
551  if (ipAddr.Set(&theIP.Addr)) return -EAFNOSUPPORT;
552 
553 // Establis the type of address we have
554 //
555  if (ipAddr.isIPType(XrdNetAddrInfo::IPv4) || ipAddr.isMapped()) theType='4';
556  else theType = '6';
557 
558 // Now format the address
559 //
560  if (theAddr && theALen > 0
561  && !ipAddr.Format(theAddr, theALen, XrdNetAddrInfo::fmtAddr, fmtopts))
562  return -EINVAL;
563 
564 // Get the port number and return it.
565 //
566  thePort = htons((theIP.Addr.sa_family == AF_INET
567  ? theIP.v4.sin_port : theIP.v6.sin6_port));
568  return static_cast<int>(thePort);
569 }
570 
571 
572 /******************************************************************************/
573 /* H o s t s */
574 /******************************************************************************/
575 
576 XrdOucTList *XrdNetUtils::Hosts(const char *hSpec, int hPort, int hWant,
577  int *sPort, const char **eText)
578 {
579  static const int hMax = 8;
580  XrdNetAddr myAddr(0), aList[hMax];
581  XrdOucTList *tList = 0;
582  const char *etext, *hName;
583  int numIP, i, k;
584 
585 // Check if the port must be in the spec and set maximum
586 //
587  if (hPort < 0) hPort = XrdNetAddr::PortInSpec;
588  if (hWant > hMax) hWant = hMax;
589  else if (hWant < 1) hWant = 1;
590 
591 // Initialze the list of addresses
592 //
593  if ((etext = aList[0].Set(hSpec, numIP, hWant, hPort)))
594  {if (eText) *eText = etext;
595  return 0;
596  }
597 
598 // Create the tlist object list without duplicates. We may have duplicates as
599 // this may be a multi-homed node and we don't want to show that here.
600 //
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);
607  }
608 
609 // All done, return the result
610 //
611  if (eText) *eText = (tList ? 0 : "unknown processing error");
612  return tList;
613 }
614 
615 /******************************************************************************/
616 /* I P F o r m a t */
617 /******************************************************************************/
618 
619 int XrdNetUtils::IPFormat(const struct sockaddr *sAddr,
620  char *bP, int bL, int opts)
621 {
622  XrdNetAddr theAddr;
623  int fmtopts = (opts & oldFmt ? XrdNetAddrInfo::old6Map4 : 0);
624 
625 // Set the address
626 //
627  if (theAddr.Set(sAddr)) return 0;
628 
629 // Now format the address
630 //
631  if (opts & noPort) fmtopts |= XrdNetAddrInfo::noPort;
632  return theAddr.Format(bP, bL, XrdNetAddrInfo::fmtAdv6, fmtopts);
633 }
634 
635 /******************************************************************************/
636 
637 int XrdNetUtils::IPFormat(int fd, char *bP, int bL, int opts)
638 {
639  XrdNetSockAddr theIP;
640  SOCKLEN_t addrSize = sizeof(theIP);
641  int rc;
642 
643 // The the address wanted
644 //
645  rc = (fd > 0 ? getpeername( fd, &theIP.Addr, &addrSize)
646  : getsockname(-fd, &theIP.Addr, &addrSize));
647  if (rc) return 0;
648 
649 // Now format it
650 //
651  return IPFormat(&theIP.Addr, bP, bL, opts);
652 }
653 
654 /******************************************************************************/
655 /* M a t c h */
656 /******************************************************************************/
657 
658 bool XrdNetUtils::Match(const char *HostName, const char *HostPat)
659 {
660  static const int maxIP = 16;
661  const char *mval;
662  int i, j, k;
663 
664 // First check if this will match right away
665 //
666  if (!strcmp(HostPat, HostName)) return true;
667 
668 // Check for an asterisk do prefix/suffix match
669 //
670  if ((mval = index(HostPat, (int)'*')))
671  { i = mval - HostPat; mval++;
672  k = strlen(HostName); j = strlen(mval);
673  if ((i+j) > k
674  || strncmp(HostName, HostPat,i)
675  || strncmp((HostName+k-j),mval,j)) return false;
676  return 1;
677  }
678 
679 // Now check for host expansion
680 //
681  i = strlen(HostPat);
682  if (i && HostPat[i-1] == '+')
683  {XrdNetAddr InetAddr[maxIP];
684  char hBuff[264];
685  if (i >= (int)sizeof(hBuff)) return false;
686  memcpy(hBuff, HostPat, i-1);
687  hBuff[i-1] = 0;
688  if (InetAddr[0].Set(hBuff, i, maxIP, 0)) return false;
689  while(i--) if ((mval = InetAddr[i].Name()) && !strcmp(mval, HostName))
690  return true;
691  }
692 
693 // No matches
694 //
695  return false;
696 }
697 
698 /******************************************************************************/
699 /* M y H o s t N a m e */
700 /******************************************************************************/
701 
702 char *XrdNetUtils::MyHostName(const char *eName, const char **eText)
703 {
704  const char *fqn = XrdNetIdentity::FQN(eText);
705 
706 // Return the appropriate result
707 //
708  if (!fqn) fqn = eName;
709  return (fqn ? strdup(fqn) : 0);
710 }
711 
712 /******************************************************************************/
713 /* N e t C o n f i g */
714 /******************************************************************************/
715 
717  const char **eText)
718 {
719  XrdNetAddr *myAddrs;
720  const char *eMsg;
721  char buff[1024];
722  NetProt hasProt = hasNone;
723  int aCnt, ifType;
724 
725 // Make sure we support this query
726 //
727  if (netquery != qryINET && netquery != qryINIF)
728  {if (eText) *eText = "unsupported NetType query";
729  return hasNone;
730  }
731 
732 // We base the nonfig of the interface addresses unless we can't query the if's
733 //
734  if (netquery == qryINIF && (ifType = XrdNetIF::GetIF((XrdOucTList **)0,0)))
735  {if (ifType & XrdNetIF::haveIPv4) hasProt = NetProt(hasProt | hasIPv4);
736  if (ifType & XrdNetIF::haveIPv6) hasProt = NetProt(hasProt | hasIPv6);
737  if (ifType & XrdNetIF::havePub4) hasProt = NetProt(hasProt | hasPub4);
738  if (ifType & XrdNetIF::havePub6) hasProt = NetProt(hasProt | hasPub6);
739  return hasProt;
740  }
741 
742 // Get our host name and initialize this object with it
743 //
744  gethostname(buff, sizeof(buff));
745  XrdOucUtils::toLower(buff);
746 
747 // Now get all of the addresses associated with this hostname
748 //
749  if ((eMsg = GetAddrs(buff, &myAddrs, aCnt, allIPv64, NoPortRaw)))
750  {if (eText) *eText = eMsg;
751  return hasNone;
752  }
753 
754 // Now run through all of the addresses to see what we have
755 //
756  for (int i = 0; i < aCnt && hasProt != hasIP64; i++)
757  { if (myAddrs[i].isIPType(XrdNetAddrInfo::IPv6))
758  {hasProt = NetProt(hasProt | hasIPv6);
759  if (!myAddrs[i].isPrivate())
760  hasProt = NetProt(hasProt | hasPub6);
761  }
762  else if (myAddrs[i].isIPType(XrdNetAddrInfo::IPv4))
763  {hasProt = NetProt(hasProt | hasIPv4);
764  if (!myAddrs[i].isPrivate())
765  hasProt = NetProt(hasProt | hasPub4);
766  }
767  }
768 
769 // Delete the array and return what we have
770 //
771  delete [] myAddrs;
772  if (hasProt == hasNone && eText) *eText = "";
773  return hasProt;
774 }
775 
776 /******************************************************************************/
777 /* P a r s e */
778 /******************************************************************************/
779 
780 bool XrdNetUtils::Parse(const char *hSpec,
781  const char **hName, const char **hNend,
782  const char **hPort, const char **hPend)
783 {
784  const char *asep = 0;
785 
786 // Parse the specification
787 //
788  if (*hSpec == '[')
789  {if (!(*hNend = index(hSpec+1, ']'))) return false;
790  *hName = hSpec+1; asep = (*hNend)+1;
791  } else {
792  *hName = hSpec;
793  if (!(*hNend = index(hSpec, ':'))) *hNend = hSpec + strlen(hSpec);
794  else asep = *hNend;
795  }
796 
797 // See if we have a port to parse. We stop on a non-alphameric.
798 //
799  if (asep && *asep == ':')
800  {*hPort = ++asep;
801  while(isalnum(*asep)) asep++;
802  if (*hPort == asep) return false;
803  *hPend = asep;
804  } else *hPort = *hPend = *hNend;
805 
806 // All done
807 //
808  return true;
809 }
810 
811 /******************************************************************************/
812 /* P o r t */
813 /******************************************************************************/
814 
815 int XrdNetUtils::Port(int fd, const char **eText)
816 {
817  XrdNetSockAddr Inet;
818  SOCKLEN_t slen = (socklen_t)sizeof(Inet);
819  int rc;
820 
821  if ((rc = getsockname(fd, &Inet.Addr, &slen)))
822  {rc = errno;
823  if (eText) setET(eText, errno);
824  return -rc;
825  }
826 
827  return static_cast<int>(ntohs(Inet.v6.sin6_port));
828 }
829 
830 /******************************************************************************/
831 /* P r o t o I D */
832 /******************************************************************************/
833 
834 #ifndef IPPROTO_TCP
835 #define IPPROTO_TCP 6
836 #endif
837 
838 int XrdNetUtils::ProtoID(const char *pname)
839 {
840 #ifdef HAVE_PROTOR
841  struct protoent pp;
842  char buff[1024];
843 #else
844  static XrdSysMutex protomutex;
845  struct protoent *pp;
846  int protoid;
847 #endif
848 
849 // Note that POSIX did include getprotobyname_r() in the last minute. Many
850 // platforms do not document this variant but just about all include it.
851 //
852 #ifdef __solaris__
853  if (!getprotobyname_r(pname, &pp, buff, sizeof(buff)))
854  return IPPROTO_TCP;
855  return pp.p_proto;
856 #elif !defined(HAVE_PROTOR)
857  protomutex.Lock();
858  if (!(pp = getprotobyname(pname))) protoid = IPPROTO_TCP;
859  else protoid = pp->p_proto;
860  protomutex.UnLock();
861  return protoid;
862 #else
863  struct protoent *ppp;
864  if (getprotobyname_r(pname, &pp, buff, sizeof(buff), &ppp))
865  return IPPROTO_TCP;
866  return pp.p_proto;
867 #endif
868 }
869 
870 /******************************************************************************/
871 /* S e r v P o r t */
872 /******************************************************************************/
873 
874 int XrdNetUtils::ServPort(const char *sName, bool isUDP, const char **eText)
875 {
876  struct addrinfo *rP = 0, myHints;
877  int rc, portnum = 0;
878 
879 // First check if this is a plain number
880 //
881  if (isdigit(*sName))
882  {char *send;
883  portnum = strtol(sName, &send, 10);
884  if (portnum > 0 && portnum < 65536 && *send == 0) return portnum;
885  if (eText) *eText = "invalid port number";
886  return 0;
887  }
888 
889 // Fill out the hints
890 //
891  memset(&myHints, 0, sizeof(myHints));
892  myHints.ai_socktype = (isUDP ? SOCK_DGRAM : SOCK_STREAM);
893 
894 // Try to find the port number
895 //
896  rc = getaddrinfo(0, sName, &myHints, &rP);
897  if (rc || !rP)
898  {if (eText) *eText = (rc ? gai_strerror(rc) : "service not found");
899  if (rP) freeaddrinfo(rP);
900  return 0;
901  }
902 
903 // Return the port number
904 //
905  portnum = int(ntohs(SIN_PORT(rP))) & 0x0000ffff;
906  freeaddrinfo(rP);
907  if (!portnum && eText) *eText = "service has no port";
908  return portnum;
909 }
910 
911 /******************************************************************************/
912 /* S e t A u t o */
913 /******************************************************************************/
914 
916 {
917 
918 // If a specific family is not specified, then determine which families to use
919 //
920  if (aOpts != onlyIPv4 && aOpts != allIPMap)
921  {int ifTypes = XrdNetIF::GetIF(0);
922  if (ifTypes & XrdNetIF::haveIPv6) aOpts = allIPMap;
923  else if (ifTypes & XrdNetIF::haveIPv4) aOpts = onlyIPv4;
924  else {autoFamily = AF_UNSPEC; autoHints = AI_V4MAPPED | AI_ADDRCONFIG;
925  return AI_V4MAPPED | AI_ADDRCONFIG;
926  }
927  }
928 
929 // If this is forced IPv4 then we know how to set the hints
930 //
931  if (aOpts == onlyIPv4)
932  {autoFamily = AF_INET; autoHints = 0; return 0;}
933 
934 // So, this is IPv6. Be as flexible as possible.
935 //
936  autoFamily = AF_INET6;
937  autoHints = AI_V4MAPPED | AI_ALL;
938  return AI_V4MAPPED | AI_ALL;
939 }
940 
941 /******************************************************************************/
942 /* Private: s e t E T */
943 /******************************************************************************/
944 
945 int XrdNetUtils::setET(const char **errtxt, int rc)
946 {
947  if (rc) *errtxt = XrdSysE2T(rc);
948  else *errtxt = "unexpected error";
949  return 0;
950 }
951 
952 /******************************************************************************/
953 /* S i n g l e t o n */
954 /******************************************************************************/
955 
956 bool XrdNetUtils::Singleton(const char *hSpec, const char **eText)
957 {
958  XrdOucTList *hList, *hNow;
959  bool isSingle;
960 
961 // Obtain a list of unique hostnames associated with this host
962 //
963  hList = Hosts(hSpec, 1234, 2, 0, eText);
964 
965 // If this is none or only one then this is a singleton
966 //
967  isSingle = !hList || hList->next == 0;
968 
969 // Free up the list of hosts
970 //
971  while((hNow = hList))
972  {hList = hList->next;
973  delete hNow;
974  };
975 
976 // All done
977 //
978  return isSingle;
979 }
980 
981 bool XrdNetUtils::ConnectWithTimeout(int sockfd, const struct sockaddr* clientAddr,size_t clientAddrLen, uint32_t timeout_sec, std::stringstream &errMsg) {
982 
983  if (!SetSockBlocking(sockfd, false, errMsg)) { // Set to non-blocking
984  close(sockfd);
985  return false;
986  }
987 
988  int result = connect(sockfd, clientAddr, clientAddrLen);
989  if (result == 0) {
990  //We've managed to connect immediately
991  // Set the socket back to blocking
992  if(!SetSockBlocking(sockfd, true, errMsg)) {
993  ::close(sockfd);
994  return false;
995  }
996  return true;
997  } else if (errno != EINPROGRESS) {
998  errMsg << "Connection failed: " << strerror(errno);
999  ::close(sockfd);
1000  return false;
1001  }
1002 
1003  struct pollfd fds;
1004  fds.fd = sockfd;
1005  fds.events = POLLOUT; // Wait for the socket to be ready to write
1006 
1007  result = poll(&fds, 1, timeout_sec * 1000); //Timeout in milliseconds
1008 
1009  if (result < 0) {
1010  errMsg << "Poll error: " << strerror(errno);
1011  ::close(sockfd);
1012  return false;
1013  } else if (result == 0) {
1014  errMsg << "Connection timed out";
1015  ::close(sockfd);
1016  return false;
1017  }
1018  // Polling succeeded
1019  if (!(fds.revents & POLLOUT)) {
1020  // We should normally not reach this code
1021  errMsg << "Poll returned without error but the corresponding socket (" << sockfd << ") is not ready to write";
1022  ::close(sockfd);
1023  return false;
1024  }
1025  // Check for potential errors on the socket after polling
1026  int so_error;
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);
1031  ::close(sockfd);
1032  return false;
1033  }
1034  // Everything succeeded, set the socket back to blocking
1035  if(!SetSockBlocking(sockfd, true, errMsg)) {
1036  ::close(sockfd);
1037  return false;
1038  }
1039  return true;
1040 }
1041 
1042 bool XrdNetUtils::SetSockBlocking(int sockfd, bool blocking, std::stringstream & errMsg) {
1043  int flags = fcntl(sockfd, F_GETFL, 0);
1044  if (flags == -1) {
1045  errMsg << "Failed to get socket flags " << strerror(errno);
1046  return false;
1047  }
1048 
1049  flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
1050 
1051  if (fcntl(sockfd, F_SETFL, flags) == -1) {
1052  errMsg << "Failed to set socket blocking/non-blocking " << strerror(errno);
1053  return false;
1054  }
1055 
1056  return true;
1057 }
struct sockaddr_in6 v6
struct sockaddr Addr
struct sockaddr_in v4
#define SIN_PORT(x)
Definition: XrdNetUtils.cc:199
#define IPPROTO_TCP
Definition: XrdNetUtils.cc:835
#define OrderXX
Definition: XrdNetUtils.cc:197
#define close(a)
Definition: XrdPosix.hh:48
#define eMsg(x)
struct myOpts opts
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
if(Avsz)
size_t strlcpy(char *dst, const char *src, size_t sz)
#define SOCKLEN_t
static const int noPort
Do not add port number.
static const int old6Map4
Use deprecated IPV6 mapped format.
bool isMapped() const
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)
int Port(int pNum=-1)
Definition: XrdNetAddr.cc:156
static const int PortInSpec
Definition: XrdNetAddr.hh:112
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition: XrdNetAddr.cc:216
static const int haveIPv4
ifList == 0 && non-local ipv4 i/f found (or'd)
Definition: XrdNetIF.hh:150
static int GetIF(XrdOucTList **ifList, const char **eText=0)
Definition: XrdNetIF.cc:413
static const int havePub6
ifList == 0 && public ipv6 i/f found (or'd)
Definition: XrdNetIF.hh:160
static const int havePub4
ifList == 0 && public ipv4 i/f found (or'd)
Definition: XrdNetIF.hh:158
static const int haveIPv6
ifList == 0 && non-local ipv6 i/f found (or'd)
Definition: XrdNetIF.hh:152
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)
Definition: XrdNetUtils.cc:658
static IPComp Compare(XrdNetSockAddr &ip1, XrdNetSockAddr &ip2, bool *psame=0)
Definition: XrdNetUtils.cc:70
static char * MyHostName(const char *eName="*unknown*", const char **eText=0)
Definition: XrdNetUtils.cc:702
static int GetSokInfo(int fd, char *theAddr, int theALen, char &theType)
Definition: XrdNetUtils.cc:533
static int Encode(const XrdNetSockAddr *sadr, char *buff, int blen, int port=-1)
Definition: XrdNetUtils.cc:155
static int IPFormat(const struct sockaddr *sAddr, char *bP, int bL, int opts=0)
Definition: XrdNetUtils.cc:619
static bool Singleton(const char *hSpec, const char **eText=0)
Definition: XrdNetUtils.cc:956
static const char * GetAddrs(const char *hSpec, XrdNetAddr *aListP[], int &aListN, AddrOpts opts=allIPMap, int pNum=PortInSpec)
Definition: XrdNetUtils.cc:274
static int Decode(XrdNetSockAddr *sadr, const char *buff, int blen)
Definition: XrdNetUtils.cc:105
static NetProt NetConfig(NetType netquery=qryINET, const char **eText=0)
Definition: XrdNetUtils.cc:716
static bool ConnectWithTimeout(int sockfd, const struct sockaddr *clientAddr, size_t clientAddrLen, uint32_t timeout_sec, std::stringstream &errMsg)
Definition: XrdNetUtils.cc:981
static int Port(int fd, const char **eText=0)
Definition: XrdNetUtils.cc:815
static int ProtoID(const char *pName)
Definition: XrdNetUtils.cc:838
static int ServPort(const char *sName, bool isUDP=false, const char **eText=0)
Definition: XrdNetUtils.cc:874
static XrdOucTList * Hosts(const char *hSpec, int hPort=-1, int hWant=8, int *sPort=0, const char **eText=0)
Definition: XrdNetUtils.cc:576
static bool Parse(const char *hSpec, const char **hName, const char **hNend, const char **hPort, const char **hPend)
Definition: XrdNetUtils.cc:780
static int SetAuto(AddrOpts aOpts=allIPMap)
Definition: XrdNetUtils.cc:915
XrdOucTList * next
Definition: XrdOucTList.hh:45
static void toLower(char *str)
const char * ipAddr
Definition: XrdNetUtils.cc:203
hpSpec(XrdNetUtils::AddrOpts opts)
Definition: XrdNetUtils.cc:217