XRootD
Loading...
Searching...
No Matches
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"
45#include "XrdNet/XrdNetIF.hh"
47#include "XrdNet/XrdNetUtils.hh"
48#include "XrdOuc/XrdOucTList.hh"
49#include "XrdSys/XrdSysE2T.hh"
51#ifndef HAVE_PROTOR
53#endif
54
55/******************************************************************************/
56/* S t a t i c M e m b e r s */
57/******************************************************************************/
58
59int XrdNetUtils::autoFamily;
60
61// The following also sets autoFamily!
62//
63int XrdNetUtils::autoHints = XrdNetUtils::SetAuto(XrdNetUtils::prefAuto);
64
65/******************************************************************************/
66/* D e c o d e */
67/******************************************************************************/
68
69int 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
119int 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
164namespace XrdNetSpace
165{
166struct 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;
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}
192using namespace XrdNetSpace;
193
194void 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
238const 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
275const 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
318const 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
359const 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
410void 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
449const 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
497int 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
540XrdOucTList *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
583int 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
601int 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
622bool 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
666char *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
743bool 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
778int 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
801int 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
837int 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
908int 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
919bool 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
944bool 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
1005bool 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)
#define IPPROTO_TCP
#define OrderXX
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
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)
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)
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 const int NoPortRaw
static bool Match(const char *hName, const char *pattern)
@ qryINET
Only consider internet protocols via DNS.
@ qryINIF
Only consider internet protocols via ifconfig.
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)
@ hasNone
Unable to determine available protocols.
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 const int PortInSpec
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 const int oldFmt
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 const int noPort
static bool Parse(const char *hSpec, const char **hName, const char **hNend, const char **hPort, const char **hPend)
static int SetAuto(AddrOpts aOpts=allIPMap)
XrdOucTList * next
const char * ipAddr
char ipAdr[MAXHOSTNAMELEN+15]
hpSpec(XrdNetUtils::AddrOpts opts)