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