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