XRootD
XrdNetRegistry.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d N e t R e g i s t r y . c c */
4 /* */
5 /* (c) 2020 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 <string>
32 #include <vector>
33 
34 #include "XrdNet/XrdNetAddr.hh"
35 #include "XrdNet/XrdNetRegistry.hh"
36 #include "XrdSys/XrdSysPthread.hh"
37 
38 /******************************************************************************/
39 /* L o c a l C l a s s e s */
40 /******************************************************************************/
41 
42 namespace
43 {
44 class regEntry
45 {
46 public:
47 
48 static regEntry *first;
49 regEntry *next;
50 regEntry *parent;
51 std::string hName;
52 std::vector<std::string> hVec;
53 uint8_t refs;
54 bool rotate;
55 
56 static void Add(regEntry *rP) {rP->next = first; first = rP;}
57 
58 static
59 regEntry *Find(const char *hName)
60  {regEntry *rP = first;
61  while(rP && (hName != rP->hName)) rP = rP->next;
62  if (rP && rP->parent) return rP->parent;
63  return rP;
64  }
65 
66  void Hold(bool want)
67  {if (want) myLock.ReadLock();
68  else myLock.UnLock();
69  }
70 
71  void Update(const char **hlist, int hlnum, bool rot)
72  {myLock.WriteLock();
73  hVec.assign(hlist, hlist+hlnum);
74  rotate = rot;
75  myLock.UnLock();
76  }
77 
78  regEntry(const char *hname, regEntry *pP)
79  : next(0), parent(pP), hName(hname), refs(0),
80  rotate(false) {}
81 
82  regEntry(const char *hname, const char *hlist[], int hlnum, bool rot)
83  : next(0), parent(0), hName(hname), refs(0), rotate(rot)
84  {hVec.assign(hlist, hlist+hlnum);}
85 
86  ~regEntry() {}
87 
88 private:
89 
90 XrdSysRWLock myLock;
91 };
92 
93 regEntry *regEntry::first = 0;
94 
95 }
96 
97 /******************************************************************************/
98 /* L o c a l S t a t i c O b j e c t s */
99 /******************************************************************************/
100 
101 namespace
102 {
103 XrdSysMutex regMutex;
104 }
105 
106 /******************************************************************************/
107 /* G e t A d d r s */
108 /******************************************************************************/
109 
110 const char *XrdNetRegistry::GetAddrs(const std::string &hSpec,
111  std::vector<XrdNetAddr> &aVec, int *ordn,
112  XrdNetUtils::AddrOpts opts, int pNum)
113 {
114  regEntry *reP;
115  unsigned int refs;
116 
117 // Find the entry
118 //
119  XrdSysMutexHelper mHelp(regMutex);
120  if (!(reP = regEntry::Find(hSpec.c_str())))
121  {aVec.clear();
122  return "pseudo host not registered";
123  }
124 
125 // Hold this entry as we don't want to hold the global lock doing DNS lookups.
126 //
127  if (reP->rotate) refs = reP->refs++;
128  else refs = 0;
129  reP->Hold(true);
130  mHelp.UnLock();
131 
132 // Resolve the the host specification (at least one must be resolvable)
133 //
134  XrdNetUtils::GetAddrs(reP->hVec, aVec, ordn, opts, refs, true);
135 
136 // Drop the hold on the entry and return result
137 //
138  reP->Hold(false);
139  if (aVec.size() == 0) return "registry entry unresolvable";
140  return 0;
141 }
142 
143 /******************************************************************************/
144 /* R e g i s t e r */
145 /******************************************************************************/
146 
147 bool XrdNetRegistry::Register(const char *hName,
148  const char *hList[], int hLNum,
149  std::string *eText, bool rotate)
150 {
151  regEntry *reP;
152 
153 // Make sure we have valid parameters
154 //
155  if (!hName || *hName != pfx || !hList || hLNum <= 0)
156  {if (eText) *eText = "invalid calling arguments";
157  return false;
158  }
159 
160 // Run through the list resolving all of the addresses. When registering, all
161 // of them must be resolvable. When running at least one must be resolvable.
162 //
163  for (int i = 0; i < hLNum; i++) if (!Resolve(hList[i], eText)) return false;
164 
165 // Do replacement or addition
166 //
167  regMutex.Lock();
168  if ((reP = regEntry::Find(hName))) reP->Update(hList, hLNum, rotate);
169  else regEntry::Add(new regEntry(hName, hList, hLNum, rotate));
170  regMutex.UnLock();
171 
172 // All done
173 //
174  return true;
175 }
176 
177 /******************************************************************************/
178 
179 bool XrdNetRegistry::Register(const char *hName, const char *hList,
180  std::string *eText, bool rotate)
181 {
182  char *comma, *hosts = strdup(hList);
183  std::vector<const char*> hVec;
184 
185 // Make sure we have valid parameters
186 //
187  if (!hName || *hName != pfx || !hList)
188  {if (eText) *eText = "invalid calling arguments";
189  return 0;
190  }
191 
192 // Check for alias creation
193 //
194  if (*hList == pfx) return SetAlias(hName, hList, eText);
195 
196 // Construct a vector of contacts
197 //
198  hVec.reserve(16);
199  hVec.push_back(hosts);
200  comma = hosts;
201  while((comma = index(comma, ',')))
202  {*comma++ = 0;
203  hVec.push_back(comma);
204  }
205 
206 // Verify that each element has a colon in it
207 //
208  for (int i = 0; i < (int)hVec.size(); i++)
209  {if (!index(hVec[i], ':'))
210  {if (eText)
211  {*eText = "port missing for '";
212  *eText += hVec[i]; *eText += "'";
213  }
214  free(hosts);
215  return false;
216  }
217  }
218 
219 // Register this contact
220 //
221  bool aOK = Register(hName, hVec.data(), (int)hVec.size(), eText, rotate);
222 
223 // Cleanup and return result
224 //
225  free(hosts);
226  return aOK;
227 }
228 
229 /******************************************************************************/
230 /* Private: R e s o l v e */
231 /******************************************************************************/
232 
233 bool XrdNetRegistry::Resolve(const char *hSpec, std::string *eText)
234 {
235  XrdNetAddr netAddr;
236  const char *emsg;
237 
238 // Validate the specification.
239 //
240  emsg = netAddr.Set(hSpec);
241 
242 // Check for errors
243 //
244  if (emsg && strncmp(emsg, "Dynamic ", 8))
245  {if (eText)
246  {*eText = "unable to resolve '"; *eText += hSpec;
247  *eText += "'; "; *eText += emsg;
248  }
249  return false;
250  }
251 
252 
253 // All done
254 //
255  return true;
256 }
257 
258 /******************************************************************************/
259 /* Private: S e t A l i a s */
260 /******************************************************************************/
261 
262 bool XrdNetRegistry::SetAlias(const char *hAlias, const char *hName,
263  std::string *eText)
264 {
265  regEntry *reP;
266  const char *eWhy = 0;
267 
268 // Verify that the source does not exist and the target does
269 //
270  regMutex.Lock();
271  if (regEntry::Find(hAlias)) eWhy = "source already exists";
272  else if (!(reP = regEntry::Find(hName))) eWhy = "target does not exist";
273  if (eWhy)
274  {regMutex.UnLock();
275  if (eText)
276  {*eText = "alias "; *eText += hAlias; *eText += " not created; ";
277  *eText += eWhy;
278  }
279  return false;
280  }
281 
282 // Add the alias
283 //
284  regEntry::Add(new regEntry(hAlias,reP));
285  regMutex.UnLock();
286  return true;
287 }
static void parent()
struct myOpts opts
int emsg(int rc, char *msg)
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition: XrdNetAddr.cc:216
static bool Register(const char *hName, const char *hList[], int hLNum, std::string *eText=0, bool rotate=false)
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 char * GetAddrs(const char *hSpec, XrdNetAddr *aListP[], int &aListN, AddrOpts opts=allIPMap, int pNum=PortInSpec)
Definition: XrdNetUtils.cc:239