XRootD
XrdFfsMisc.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* XrdFfsMisc.cc Miscellanies functions */
3 /* */
4 /* (c) 2010 by the Board of Trustees of the Leland Stanford, Jr., University */
5 /* All Rights Reserved */
6 /* Author: Wei Yang (SLAC National Accelerator Laboratory, 2009) */
7 /* Contract DE-AC02-76-SFO0515 with the Department of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 
30 #define _FILE_OFFSET_BITS 64
31 #include <cstring>
32 #include <sys/types.h>
33 //#include <sys/xattr.h>
34 #include <iostream>
35 #include <libgen.h>
36 #include <unistd.h>
37 //#include <netdb.h>
38 #include <pwd.h>
39 #include <grp.h>
40 #include <ctime>
41 #include <pthread.h>
42 #include <cstdio>
43 #include <syslog.h>
44 
45 #include "XrdNet/XrdNetAddr.hh"
46 #include "XrdNet/XrdNetUtils.hh"
47 #include "XrdOuc/XrdOucECMsg.hh"
49 #include "XrdSec/XrdSecEntity.hh"
50 #include "XrdSecsss/XrdSecsssID.hh"
51 #include "XrdFfs/XrdFfsDent.hh"
52 #include "XrdFfs/XrdFfsFsinfo.hh"
53 #include "XrdFfs/XrdFfsMisc.hh"
54 #include "XrdFfs/XrdFfsPosix.hh"
55 #include "XrdFfs/XrdFfsQueue.hh"
57 
58 #ifdef __cplusplus
59  extern "C" {
60 #endif
61 
62 #define MAXROOTURLLEN 1024 // this is also defined in other files
63 
64 #define nXrdConnPerUsr 8;
65 short iXrdConnPerUsr = 0;
66 pthread_mutex_t url_mlock;
67 
68 char XrdFfsMisc_get_current_url(const char *oldurl, char *newurl)
69 {
70  struct stat stbuf;
71 
72 /* if it is a directory, return oldurl */
73  if (XrdFfsPosix_stat(oldurl, &stbuf) == 0 && S_ISDIR(stbuf.st_mode))
74  {
75  strcpy(newurl, oldurl);
76  return 1;
77  }
78 
80  XrdPosixAdmin adm(oldurl,ecMsg);
81  if (adm.isOK() && adm.Stat())
82  {
83 // We might have been redirected to a destination server. Better
84 // to remember it and use only this one as output.
85 // if (stat && adm->GetCurrentUrl().IsValid())
86 // {
87 // strcpy(newurl, adm->GetCurrentUrl().GetUrl().c_str());
88 // delete adm;
89  strcpy(newurl, oldurl); // This needs to change!!!
90  return 1;
91  }
92  return 0;
93 }
94 
95 char* XrdFfsMisc_getNameByAddr(char* ipaddr)
96 {
97  XrdNetAddr netAddr;
98  const char *theName;
99  if (netAddr.Set(ipaddr,0) || !(theName = netAddr.Name())) theName = ipaddr;
100  return strdup(theName);
101 }
102 
103 int XrdFfsMisc_get_all_urls_real(const char *oldurl, char **newurls, const int nnodes)
104 {
106  XrdPosixAdmin adm(oldurl,ecMsg);
107  XrdCl::URL *uVec;
108  int i, rval = 0;
109 
110  if (!adm.isOK() || !(uVec = adm.FanOut(rval))) return -1;
111 
112  if (rval > nnodes) rval = -1;
113  else for (i = 0; i < rval; i++)
114  { strncpy(newurls[i], uVec[i].GetURL().c_str(), MAXROOTURLLEN -1); newurls[i][MAXROOTURLLEN -1] = '\0'; }
115 
116  delete [] uVec;
117  return rval;
118 }
119 
120 /*
121  function XrdFfsMisc_get_all_urls() has the same interface as XrdFfsMisc_get_all_urls_real(), but
122  used a cache to reduce unnecessary queries to the redirector
123 */
124 
129 pthread_mutex_t XrdFfsMiscUrlcache_mutex = PTHREAD_MUTEX_INITIALIZER;
131 
133 {
134  return XrdFfsMiscNcachedurls;
135 }
136 
137 void XrdFfsMisc_set_Urlcachelife(const char *urlcachelife)
138 {
139  int t, len;
140  char *life = strdup(urlcachelife);
141  char last = 's';
142 
143  if (life == NULL) return;
144 
145  len = strlen(life);
146  if (! isdigit(life[len-1]))
147  {
148  last = life[len-1];
149  life[len-1] = '\0';
150  }
151  sscanf(life, "%d", &t);
152  XrdFfsMiscUrlcachelife = (time_t) t;
153  life[len-1] = last;
154  switch (last)
155  {
156  case 'm': /* minute */
158  break;
159  case 'h': /* hour */
160  XrdFfsMiscUrlcachelife *= 3600;
161  break;
162  case 'd': /* day */
163  XrdFfsMiscUrlcachelife *= 3600*24;
164  break;
165  default: /* second */
166  ;
167  }
168  free(life);
169  return;
170 }
171 
172 int XrdFfsMisc_get_all_urls(const char *oldurl, char **newurls, const int nnodes)
173 {
174  time_t currtime;
175  int i, nurls;
176 
177  pthread_mutex_lock(&XrdFfsMiscUrlcache_mutex);
178 
179  currtime = time(NULL);
180 /* setting the cache to effectively not expire will let us know if a host is down */
181  if (XrdFfsMiscCururl[0] == '\0' ||
183  strcmp(XrdFfsMiscCururl, oldurl) != 0)
184  {
185  for (i = 0; i < XrdFfsMiscNcachedurls; i++)
186  if (XrdFfsMiscUrlcache[i] != NULL) free(XrdFfsMiscUrlcache[i]);
187  for (i = 0; i < XrdFfs_MAX_NUM_NODES; i++)
188  XrdFfsMiscUrlcache[i] = (char*) malloc(MAXROOTURLLEN);
189 
190  XrdFfsMiscUrlcachetime = currtime;
191  strcpy(XrdFfsMiscCururl, oldurl);
193  for (i = XrdFfsMiscNcachedurls; i < XrdFfs_MAX_NUM_NODES; i++)
194  if (XrdFfsMiscUrlcache[i] != NULL) free(XrdFfsMiscUrlcache[i]);
195  }
196 
197  nurls = XrdFfsMiscNcachedurls;
198  for (i = 0; i < nurls; i++)
199  {
200  newurls[i] = (char*) malloc(MAXROOTURLLEN);
201  strncpy(newurls[i], XrdFfsMiscUrlcache[i], MAXROOTURLLEN -1);
202  newurls[i][MAXROOTURLLEN-1] = '\0';
203  }
204 
205  pthread_mutex_unlock(&XrdFfsMiscUrlcache_mutex);
206  return nurls;
207 }
208 
210 {
211  XrdNetAddr uAddr;
212  int i, n = 0;
213  const char *netName;
214  const char *hName, *hNend, *hPort, *hPend;
215  char *url, *rc, *hostip, hsep;
216 
217  rc = (char*)malloc(sizeof(char) * XrdFfs_MAX_NUM_NODES * MAXROOTURLLEN);
218  rc[0] = '\0';
219  pthread_mutex_lock(&XrdFfsMiscUrlcache_mutex);
220  for (i = 0; i < XrdFfsMiscNcachedurls; i++)
221  {
222  url = strdup(XrdFfsMiscUrlcache[i]);
223  hostip = &url[7];
224  if (XrdNetUtils::Parse(hostip, &hName, &hNend, &hPort, &hPend))
225  {n++;
226  hsep = *hNend;
227  hostip[hNend-hostip] = 0;
228  hostip[hPend-hostip] = 0;
229  if (uAddr.Set(hName,0) || !(netName = uAddr.Name()))
230  {hostip[hNend-hostip] = hsep;
231  hName = hostip;
232  hPend = hNend;
233  }
234  strcat(rc, hName);
235  if (hPort != hNend)
236  {strcat(rc, ":");
237  strcat(rc, hPort);
238  }
239  strcat(rc, "\n");
240  }
241  free(url);
242  }
243  pthread_mutex_unlock(&XrdFfsMiscUrlcache_mutex);
244  strcpy(list, rc);
245  free(rc);
246  return n;
247 }
248 
249 void XrdFfsMisc_refresh_url_cache(const char* url)
250 {
251  int i, nurls;
252  char *surl, **turls;
253 
254  turls = (char**) malloc(sizeof(char*) * XrdFfs_MAX_NUM_NODES);
255 
256 // invalid the cache first
257  pthread_mutex_lock(&XrdFfsMiscUrlcache_mutex);
259  pthread_mutex_unlock(&XrdFfsMiscUrlcache_mutex);
260 
261  if (url != NULL)
262  surl = strdup(url);
263  else
264  surl = strdup(XrdFfsMiscCururl);
265 
266  nurls = XrdFfsMisc_get_all_urls(surl, turls, XrdFfs_MAX_NUM_NODES);
267 
268  free(surl);
269  for (i = 0; i < nurls; i++) free(turls[i]);
270  free(turls);
271 }
272 
273 void XrdFfsMisc_logging_url_cache(const char* url)
274 {
275  int i;
276  char *hostlist, *p1, *p2;
277 
278  if (url != NULL) XrdFfsMisc_refresh_url_cache(url);
279 
280  hostlist = (char*) malloc(sizeof(char) * XrdFfs_MAX_NUM_NODES * 256);
282 
283  syslog(LOG_INFO, "INFO: use the following %d data servers :", i);
284  p1 = hostlist;
285  p2 = strchr(p1, '\n');
286  while (p2 != NULL)
287  {
288  p2[0] = '\0';
289  syslog(LOG_INFO, " %s", p1);
290  p1 = p2 +1;
291  p2 = strchr(p1, '\n');
292  }
293  free(hostlist);
294 }
295 
296 void XrdFfsMisc_xrd_init(const char *rdrurl, const char *urlcachelife, int startQueue)
297 {
298  static int OneTimeInitDone = 0;
299 
300 // Do not execute this more than once
301 //
302  if (OneTimeInitDone) return;
303  OneTimeInitDone = 1;
304 
305 // EnvPutInt(NAME_FIRSTCONNECTMAXCNT,2);
306 // EnvPutInt(NAME_DATASERVERCONN_TTL, 99999999);
307 // EnvPutInt(NAME_LBSERVERCONN_TTL, 99999999);
308 // EnvPutInt(NAME_READAHEADSIZE,0);
309 // EnvPutInt(NAME_READCACHESIZE,0);
310 // EnvPutInt(NAME_REQUESTTIMEOUT, 30);
311  XrdPosixConfig::SetEnv("WorkerThreads", 50);
312 
313  if (getenv("XROOTDFS_SECMOD") != NULL && !strcmp(getenv("XROOTDFS_SECMOD"), "sss"))
315 
316  openlog("XrootdFS", LOG_ODELAY | LOG_PID, LOG_DAEMON);
317 
318  XrdFfsMisc_set_Urlcachelife(urlcachelife);
321 
322 #ifndef NOUSE_QUEUE
323  if (startQueue)
324  {
325  if (getenv("XROOTDFS_NWORKERS") != NULL)
326  XrdFfsQueue_create_workers(atoi(getenv("XROOTDFS_NWORKERS")));
327  else
329 
330  syslog(LOG_INFO, "INFO: Starting %d workers", XrdFfsQueue_count_workers());
331  }
332 #endif
333 
334  pthread_mutex_init(&url_mlock, NULL);
335 
337 }
338 
339 // convert an unsigned decimal int to its base24 string
340 
341 void toChar(unsigned int r, char *d24)
342 {
343  const char alpha[] = "0123456789abcdefghijklmn";
344  char tmp[8];
345  memcpy(tmp, d24, 8);
346  memcpy(d24+1, tmp, 8);
347  d24[0] = alpha[r];
348  return;
349 }
350 
351 void decTo24(unsigned int d, char *d24)
352 {
353  unsigned int r = d % 24;
354  toChar(r, d24);
355  if ((d - r) != 0) decTo24((d-r)/24, d24);
356  return;
357 }
358 
359 char* ntoa24(unsigned int d) { // caller is repsonsible to free the memory
360  char *d24 = (char*) malloc(9);
361  memset(d24, 0, 9);
362  decTo24(d, d24);
363  return d24;
364 }
365 
366 /* SSS security module */
367 
369 bool XrdFfsMiscSecsss = false;
370 
372 {
373  XrdFfsMiscSecsss = true;
375 
376 /* Enforce "sss" security */
377  setenv("XrdSecPROTOCOL", "sss", 1);
378 }
379 
380 void XrdFfsMisc_xrd_secsss_register(uid_t user_uid, gid_t user_gid, int *id)
381 {
382  struct passwd pw, *pwp;
383  struct group gr, *grp;
384  char user_num[9], *pwbuf, *grbuf, *tmp;
385  static size_t pwbuflen = 0;
386  static size_t grbuflen = 0;
387 
388  if (pwbuflen == 0) pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
389  if (grbuflen == 0) grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
390 
391  XrdSecEntity XrdFfsMiscUent("");
392 
393  tmp = ntoa24((unsigned int)user_uid);
394  memcpy(user_num, tmp, 9);
395  free(tmp);
396 
397  if (id != NULL) {
398  pthread_mutex_lock(&url_mlock);
399  *id = iXrdConnPerUsr +1; // id = 1 to nXrdConnPerUsr+1 (8)
401  pthread_mutex_unlock(&url_mlock);
402  user_num[strlen(user_num)] = *id + 48; // this require that *id stay as single digit.
403  }
404  else
405  user_num[strlen(user_num)] = 48; // id = NULL
406 
407  if (XrdFfsMiscSecsss)
408  {
409  pwbuf = (char*) malloc(pwbuflen);
410  getpwuid_r(user_uid, &pw, pwbuf, pwbuflen, &pwp);
411  grbuf = (char*) malloc(grbuflen);
412  getgrgid_r(user_gid, &gr, grbuf, grbuflen, &grp);
413 
414  XrdFfsMiscUent.name = pw.pw_name;
415  XrdFfsMiscUent.grps = gr.gr_name;
416  XrdFfsMiscUent.uid = user_uid;
417  XrdFfsMiscUent.gid = user_gid;
418  XrdFfsMiscSssid->Register(user_num, &XrdFfsMiscUent, 0);
419  free(pwbuf);
420  free(grbuf);
421  }
422 }
423 
424 void XrdFfsMisc_xrd_secsss_editurl(char *url, uid_t user_uid, int *id)
425 {
426  char user_num[9], nurl[MAXROOTURLLEN], *tmp;
427 
428 // Xrootd proxy also use some of the stat()/unlink(), etc funcitons here, without user "sss". It use the default
429 // connection login name. Don't change this behavior. (so for proxy, use no "sss", and always have *id = 0
430  if (id != NULL || XrdFfsMiscSecsss)
431  {
432  tmp = ntoa24(user_uid);
433  memcpy(user_num, tmp, 9);
434  free(tmp);
435  if (id == NULL) user_num[strlen(user_num)] = 48;
436  else user_num[strlen(user_num)] = *id + 48;
437 
438  nurl[0] = '\0';
439  strncat(nurl, "root://", 8);
440  strncat(nurl, user_num, 9);
441  strncat(nurl, "@", 2);
442  strncat(nurl, &(url[7]), MAXROOTURLLEN-17);
443  strncpy(url, nurl, MAXROOTURLLEN);
444  }
445 }
446 
447 #ifdef __cplusplus
448  }
449 #endif
void XrdFfsDent_cache_init()
Definition: XrdFfsDent.cc:207
void XrdFfsMisc_set_Urlcachelife(const char *urlcachelife)
Definition: XrdFfsMisc.cc:137
void XrdFfsMisc_logging_url_cache(const char *url)
Definition: XrdFfsMisc.cc:273
void XrdFfsMisc_xrd_init(const char *rdrurl, const char *urlcachelife, int startQueue)
Definition: XrdFfsMisc.cc:296
bool XrdFfsMiscSecsss
Definition: XrdFfsMisc.cc:369
char * XrdFfsMiscUrlcache[XrdFfs_MAX_NUM_NODES]
Definition: XrdFfsMisc.cc:126
void XrdFfsMisc_xrd_secsss_init()
Definition: XrdFfsMisc.cc:371
pthread_mutex_t XrdFfsMiscUrlcache_mutex
Definition: XrdFfsMisc.cc:129
int XrdFfsMiscNcachedurls
Definition: XrdFfsMisc.cc:127
int XrdFfsMisc_get_list_of_data_servers(char *list)
Definition: XrdFfsMisc.cc:209
char * ntoa24(unsigned int d)
Definition: XrdFfsMisc.cc:359
void decTo24(unsigned int d, char *d24)
Definition: XrdFfsMisc.cc:351
char XrdFfsMisc_get_current_url(const char *oldurl, char *newurl)
Definition: XrdFfsMisc.cc:68
void XrdFfsMisc_xrd_secsss_register(uid_t user_uid, gid_t user_gid, int *id)
Definition: XrdFfsMisc.cc:380
#define nXrdConnPerUsr
Definition: XrdFfsMisc.cc:64
char * XrdFfsMisc_getNameByAddr(char *ipaddr)
Definition: XrdFfsMisc.cc:95
int XrdFfsMisc_get_number_of_data_servers()
Definition: XrdFfsMisc.cc:132
void XrdFfsMisc_xrd_secsss_editurl(char *url, uid_t user_uid, int *id)
Definition: XrdFfsMisc.cc:424
time_t XrdFfsMiscUrlcachetime
Definition: XrdFfsMisc.cc:128
XrdSecsssID * XrdFfsMiscSssid
Definition: XrdFfsMisc.cc:368
int XrdFfsMisc_get_all_urls(const char *oldurl, char **newurls, const int nnodes)
Definition: XrdFfsMisc.cc:172
pthread_mutex_t url_mlock
Definition: XrdFfsMisc.cc:66
int XrdFfsMisc_get_all_urls_real(const char *oldurl, char **newurls, const int nnodes)
Definition: XrdFfsMisc.cc:103
char XrdFfsMiscCururl[MAXROOTURLLEN]
Definition: XrdFfsMisc.cc:125
short iXrdConnPerUsr
Definition: XrdFfsMisc.cc:65
#define MAXROOTURLLEN
Definition: XrdFfsMisc.cc:62
void XrdFfsMisc_refresh_url_cache(const char *url)
Definition: XrdFfsMisc.cc:249
void toChar(unsigned int r, char *d24)
Definition: XrdFfsMisc.cc:341
time_t XrdFfsMiscUrlcachelife
Definition: XrdFfsMisc.cc:130
#define XrdFfs_MAX_NUM_NODES
Definition: XrdFfsMisc.hh:34
int XrdFfsPosix_stat(const char *path, struct stat *buf)
Definition: XrdFfsPosix.cc:66
int XrdFfsQueue_count_workers()
Definition: XrdFfsQueue.cc:254
int XrdFfsQueue_create_workers(int n)
Definition: XrdFfsQueue.cc:192
int stat(const char *path, struct stat *buf)
URL representation.
Definition: XrdClURL.hh:31
const char * Name(const char *eName=0, const char **eText=0)
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition: XrdNetAddr.cc:216
static bool Parse(const char *hSpec, const char **hName, const char **hNend, const char **hPort, const char **hPend)
Definition: XrdNetUtils.cc:745
bool Stat(mode_t *flags=0, time_t *mtime=0)
XrdCl::URL * FanOut(int &num)
static void SetEnv(const char *kword, int kval)
gid_t gid
Unix gid or 0 if none.
Definition: XrdSecEntity.hh:87
char * grps
Entity's group name(s)
Definition: XrdSecEntity.hh:73
uid_t uid
Unix uid or 0 if none.
Definition: XrdSecEntity.hh:86
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
bool Register(const char *lgnid, const XrdSecEntity *Ident, bool doReplace=false, bool defer=false)
Definition: XrdSecsssID.cc:224
thread_local XrdOucECMsg ecMsg