XRootD
XrdXrootdAdmin.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d X r o o t d A d m i n . c c */
4 /* */
5 /* (c) 2005 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 <fcntl.h>
32 #include <cstdlib>
33 #include <cstring>
34 #include <unistd.h>
35 #include <netinet/in.h>
36 #include <sys/types.h>
37 
38 #include "Xrd/XrdLink.hh"
39 #include "XrdNet/XrdNetSocket.hh"
40 #include "XrdSys/XrdSysError.hh"
41 #include "XrdSys/XrdSysPlatform.hh"
42 #include "XrdSys/XrdSysPthread.hh"
43 #include "XrdOuc/XrdOucTList.hh"
48 
49 /******************************************************************************/
50 /* G l o b a l s & S t a t i c s */
51 /******************************************************************************/
52 
54 
55  XrdSysError *XrdXrootdAdmin::eDest;
56 
57  XrdXrootdAdmin::JobTable *XrdXrootdAdmin::JobList = 0;
58 
59 /******************************************************************************/
60 /* E x t e r n a l T h r e a d I n t e r f a c e s */
61 /******************************************************************************/
62 
63 void *XrdXrootdInitAdmin(void *carg)
65  return Admin.Start((XrdNetSocket *)carg);
66  }
67 
68 void *XrdXrootdLoginAdmin(void *carg)
70  Admin->Login(*(int *)carg);
71  delete Admin;
72  return (void *)0;
73  }
74 
75 /******************************************************************************/
76 /* a d d J o b */
77 /******************************************************************************/
78 
79 void XrdXrootdAdmin::addJob(const char *jname, XrdXrootdJob *jp)
80 {
81  JobTable *jTabp = new JobTable();
82 
83  jTabp->Jname = strdup(jname);
84  jTabp->Job = jp;
85  jTabp->Next = JobList;
86  JobList = jTabp;
87 }
88 
89 /******************************************************************************/
90 /* I n i t */
91 /******************************************************************************/
92 
94 {
95  const char *epname = "Init";
96  pthread_t tid;
97 
98  eDest = erp;
99  if (XrdSysThread::Run(&tid, XrdXrootdInitAdmin, (void *)asock,
100  0, "Admin traffic"))
101  {eDest->Emsg(epname, errno, "start admin");
102  return 0;
103  }
104  return 1;
105 }
106 
107 /******************************************************************************/
108 /* L o g i n */
109 /******************************************************************************/
110 
111 void XrdXrootdAdmin::Login(int socknum)
112 {
113  const char *epname = "Admin";
114  char *tp;
115 
116 // Attach the socket FD to a stream
117 //
118  Stream.SetEroute(eDest);
119  Stream.AttachIO(socknum, socknum);
120 
121 // Get the first request
122 //
123  if (!Stream.GetLine())
124  {eDest->Emsg(epname, "No admin login specified");
125  return;
126  }
127 
128 // The first request better be: <reqid> login <name>
129 //
130  if (getreqID()
131  || !(tp = Stream.GetToken())
132  || strcmp("login", tp)
133  || do_Login())
134  {eDest->Emsg(epname, "Invalid admin login sequence");
135  return;
136  }
137 
138 // Document the login and go process the stream
139 //
140  eDest->Emsg(epname, "Admin", TraceID, "logged in");
141  Xeq();
142 }
143 
144 /******************************************************************************/
145 /* S t a r t */
146 /******************************************************************************/
147 
149 {
150  const char *epname = "Start";
151  int InSock;
152  pthread_t tid;
153 
154 // Accept connections in an endless loop
155 //
156  while(1) if ((InSock = AdminSock->Accept()) >= 0)
157  {if (XrdSysThread::Run(&tid,XrdXrootdLoginAdmin,(void *)&InSock))
158  {eDest->Emsg(epname, errno, "start admin");
159  close(InSock);
160  }
161  } else eDest->Emsg(epname, errno, "accept connection");
162  return (void *)0;
163 }
164 
165 /******************************************************************************/
166 /* P r i v a t e M e t h o d s */
167 /******************************************************************************/
168 /******************************************************************************/
169 /* d o _ C j */
170 /******************************************************************************/
171 
172 int XrdXrootdAdmin::do_Cj()
173 {
174  const char *fmt1 = "<resp id=\"%s\"><rc>0</rc>";
175  const char *fmt2 = "<num>%d</num></resp>\n";
176  char *tp, buff[1024];
177  XrdXrootdJob *jobp;
178  JobTable *jTabp;
179  int i, rc;
180 
181 // The next token needs to be job type
182 //
183  if (!(tp = Stream.GetToken()))
184  {sendErr(8, "cj", "job type not specified.");
185  return -1;
186  }
187 
188 // Run through the list of valid job types
189 //
190  jTabp = JobList;
191  while(jTabp && strcmp(tp, jTabp->Jname)) jTabp = jTabp->Next;
192 
193 // See if we have a real job list here
194 //
195  if (jTabp) jobp = jTabp->Job;
196  else if (!strcmp(tp, "*")) jobp = 0;
197  else {sendErr(8, "cj", "invalid job type specified.");
198  return -1;
199  }
200 
201 // Get optional key
202 //
203  tp = Stream.GetToken();
204 
205 // Send the header of the response
206 //
207  i = sprintf(buff, fmt1, reqID);
208  if (Stream.Put(buff, i)) return -1;
209 
210 // Cancel the jobs
211 //
212  if (jobp) rc = jobp->Cancel(tp);
213  else {jTabp = JobList; rc = 0;
214  while(jTabp) {rc += jTabp->Job->Cancel(tp); jTabp = jTabp->Next;}
215  }
216 
217 // Now print the end-framing
218 //
219  i = sprintf(buff, fmt2, rc);
220  return Stream.Put(buff, i);
221 }
222 
223 /******************************************************************************/
224 /* d o _ L o g i n */
225 /******************************************************************************/
226 
227 int XrdXrootdAdmin::do_Login()
228 {
229  const char *fmt="<resp id=\"%s\"><rc>0</rc><v>" kXR_PROTOCOLVSTRING
230  "</v></resp>\n";
231  char *tp, buff[1024];
232  int blen;
233 
234 // Process: login <name>
235 //
236  if (!(tp = Stream.GetToken()))
237  {eDest->Emsg("do_Login", "login name not specified");
238  return 0;
239  } else strlcpy(TraceID, tp, sizeof(TraceID));
240 
241 // Provide good response
242 //
243  blen = snprintf(buff, sizeof(buff)-1, fmt, reqID);
244  buff[sizeof(buff)-1] = '\0';
245  return Stream.Put(buff, blen);
246 }
247 
248 /******************************************************************************/
249 /* d o _ L s c */
250 /******************************************************************************/
251 
252 int XrdXrootdAdmin::do_Lsc()
253 {
254  const char *fmt1 = "<resp id=\"%s\"><rc>0</rc><conn>";
255  const char *fmt2 = "</conn></resp>\n";
256  static int fmt2len = strlen(fmt2);
257  char buff[1024];
258  const char *mdat[3] = {buff, " ", 0};
259  int mlen[3] = {0, 1, 0};
260  int i, rc, curr = -1;
261 
262 // Handle: list <target>
263 //
264  if ((rc = getTarget("lsc"))) return 0;
265 
266 // Send the header of the response
267 //
268  i = sprintf(buff, fmt1, reqID);
269  if (Stream.Put(buff, i)) return -1;
270 
271 // Return back matching client list
272 //
273  while((mlen[0] = XrdLink::getName(curr, buff, sizeof(buff), &Target)))
274  if (Stream.Put(mdat, mlen)) return -1;
275  return Stream.Put(fmt2, fmt2len);
276 }
277 
278 /******************************************************************************/
279 /* d o _ L s d */
280 /******************************************************************************/
281 
282 int XrdXrootdAdmin::do_Lsd()
283 {
284  const char *fmt1 = "<resp id=\"%s\"><rc>0</rc>";
285  const char *fmt2 = "<c r=\"%c\" t=\"%lld\" v=\"%d\" m=\"%s\">";
286  const char *fmt2a= "<io u=\"%d\"><nf>%d</nf><p>%lld<n>%d</n></p>"
287  "<i>%lld<n>%d</n></i><o>%lld<n>%d</n></o>"
288  "<s>%d</s><t>%d</t></io>";
289  const char *fmt3 = "<auth p=\"%s\"><n>";
290  const char *fmt3e= "</r></auth>";
291  const char *fmt4 = "</resp>\n";
292  static int fmt3elen= strlen(fmt3e);
293  static int fmt4len = strlen(fmt4);
294  char ctyp, monit[3], *mm, cname[1024], buff[100];
295  char aprot[XrdSecPROTOIDSIZE+2], abuff[32], iobuff[256];
296  const char *mdat[24]= {buff, cname, iobuff};
297  int mlen[24]= {0};
298  long long conn, inBytes, outBytes;
299  int i, rc, cver, inuse, stalls, tardies, curr = -1;
300  XrdLink *lp;
301  XrdProtocol *xp;
302  XrdXrootdProtocol *pp;
303 
304 // Handle: list <target>
305 //
306  if ((rc = getTarget("lsd"))) return 0;
307 
308 // Send the header of the response
309 //
310  i = sprintf(buff, fmt1, reqID);
311  if (Stream.Put(buff, i)) return -1;
312 
313 // Return back matching client list
314 //
315  while((lp = XrdLink::Find(curr, &Target)))
316  if ((xp = lp->getProtocol())
317  && (pp = dynamic_cast<XrdXrootdProtocol *>(xp)))
318  {cver = int(pp->CapVer);
319  ctyp = 'u';
320  conn = static_cast<long long>(lp->timeCon());
321  mm = monit;
322  if (pp->Monitor.Files()) *mm++ = 'f';
323  if (pp->Monitor.InOut()) *mm++ = 'i';
324  *mm = '\0';
325  inuse = lp->getIOStats(inBytes, outBytes, stalls, tardies);
326  mlen[0] = sprintf(buff, fmt2, ctyp, conn, cver, monit);
327  mlen[1] = lp->Client(cname, sizeof(cname));
328  mlen[2] = sprintf(iobuff, fmt2a,inuse-1,pp->numFiles,pp->totReadP,
329  (pp->cumReadP + pp->numReadP),
330  inBytes, (pp->cumWrites+ pp->numWrites +
331  pp->cumWritV + pp->numWritV),
332  outBytes,(pp->cumReads + pp->numReads +
333  pp->cumReadV + pp->numReadV),
334  stalls, tardies);
335  i = 3;
336  if ((pp->Client) && pp->Client != &(pp->Entity))
337  {strncpy(aprot, pp->Client->prot, XrdSecPROTOIDSIZE);
338  aprot[XrdSecPROTOIDSIZE] = '\0';
339  mdat[i] = abuff;
340  mlen[i++]= sprintf(abuff, fmt3, aprot);
341  i = 1;
342  if (pp->Client->name && (mlen[i] = strlen(pp->Client->name)))
343  mdat[i++] = pp->Client->name;
344  mdat[i] = "</n><h>"; mlen[i++] = 7;
345  if (pp->Client->host && (mlen[i] = strlen(pp->Client->host)))
346  mdat[i++] = pp->Client->host;
347  mdat[i] = "</h><o>"; mlen[i++] = 7;
348  if (pp->Client->vorg && (mlen[i] = strlen(pp->Client->vorg)))
349  mdat[i++] = pp->Client->vorg;
350  mdat[i] = "</o><r>"; mlen[i++] = 7;
351  if (pp->Client->role && (mlen[i] = strlen(pp->Client->role)))
352  mdat[i++] = pp->Client->role;
353  mdat[i] = fmt3e; mlen[i++] = fmt3elen;
354  }
355  mdat[i] = "</c>"; mlen[i++] = 4;
356  mdat[i] = 0; mlen[i] = 0;
357  if (Stream.Put(mdat, mlen)) {lp->setRef(-1); return -1;}
358  }
359  return Stream.Put(fmt4, fmt4len);
360 }
361 
362 /******************************************************************************/
363 /* d o _ L s j */
364 /******************************************************************************/
365 
366 int XrdXrootdAdmin::do_Lsj()
367 {
368  const char *fmt1 = "<resp id=\"%s\"><rc>0</rc>";
369  const char *fmt2 = "</resp>\n";
370  static int fmt2len = strlen(fmt2);
371  char *tp, buff[1024];
372  XrdXrootdJob *jobp;
373  JobTable *jTabp;
374  int i, rc = 0;
375 
376 // The next token needs to be job type
377 //
378  if (!(tp = Stream.GetToken()))
379  {sendErr(8, "lsj", "job type not specified.");
380  return -1;
381  }
382 
383 // Run through the list of valid job types
384 //
385  jTabp = JobList;
386  while(jTabp && strcmp(tp, jTabp->Jname)) jTabp = jTabp->Next;
387 
388 // See if we have a real job list here
389 //
390  if (jTabp) jobp = jTabp->Job;
391  else if (!strcmp(tp, "*")) jobp = 0;
392  else {sendErr(8, "lsj", "invalid job type specified.");
393  return -1;
394  }
395 
396 // Send the header of the response
397 //
398  i = sprintf(buff, fmt1, reqID);
399  if (Stream.Put(buff, i)) return -1;
400 
401 // List the jobs
402 //
403  if (jobp) rc = do_Lsj_Xeq(jobp);
404  else {jTabp = JobList;
405  while(jTabp && !(rc = do_Lsj_Xeq(jTabp->Job))) jTabp = jTabp->Next;
406  }
407 
408 // Now print the end-framing
409 //
410  return (rc ? rc : Stream.Put(fmt2, fmt2len));
411 }
412 
413 /******************************************************************************/
414 /* d o _ L s j _ X e q */
415 /******************************************************************************/
416 
417 int XrdXrootdAdmin::do_Lsj_Xeq(XrdXrootdJob *jp)
418 {
419  XrdOucTList *tp, *tpprev;
420  int rc = 0;
421 
422  if ((tp = jp->List()))
423  while(tp && !(rc = Stream.Put(tp->text, tp->val)))
424  {tpprev = tp; tp = tp->next; delete tpprev;}
425 
426  while(tp) {tpprev = tp; tp = tp->next; delete tpprev;}
427 
428  return rc;
429 }
430 
431 /******************************************************************************/
432 /* d o _ M s g */
433 /******************************************************************************/
434 
435 int XrdXrootdAdmin::do_Msg()
436 {
437  char *msg;
438  int rc, mlen;
439 
440 // Handle: msg <target> [msg]
441 //
442  if ((rc = getTarget("msg", &msg))) return 0;
443 
444 // Get optional message
445 //
446  msg = getMsg(msg, mlen);
447 // Send off the unsolicited response
448 //
449  if (msg) return sendResp("msg", kXR_asyncms, msg, mlen);
450  else return sendResp("msg", kXR_asyncms);
451 }
452 
453 /******************************************************************************/
454 /* g e t M s g */
455 /******************************************************************************/
456 
457 char *XrdXrootdAdmin::getMsg(char *msg, int &mlen)
458 {
459  if (msg) while(*msg == ' ') msg++;
460  if (msg && *msg) mlen = strlen(msg)+1;
461  else {msg = 0; mlen = 0;}
462  return msg;
463 }
464 
465 /******************************************************************************/
466 /* g e t r e q I D */
467 /******************************************************************************/
468 
469 int XrdXrootdAdmin::getreqID()
470 {
471  char *tp;
472 
473  if (!(tp = Stream.GetToken()))
474  {reqID[0] = '?'; reqID[1] = '\0';
475  return sendErr(4, "request", "id not specified.");
476  }
477 
478  if (strlen(tp) >= sizeof(reqID))
479  {reqID[0] = '?'; reqID[1] = '\0';
480  return sendErr(4, "request", "id too long.");
481  }
482 
483  strcpy(reqID, tp);
484  return 0;
485 }
486 
487 /******************************************************************************/
488 /* g e t T a r g e t */
489 /******************************************************************************/
490 /* Returns 0 if a target was found, otherwise -1 */
491 
492 int XrdXrootdAdmin::getTarget(const char *act, char **rest)
493 {
494  char *tp;
495 
496 // Get the target
497 //
498  if (!(tp = Stream.GetToken(rest)))
499  {sendErr(8, act, "target not specified.");
500  return -1;
501  }
502  Target.Set(tp);
503 
504  return 0;
505 }
506 
507 /******************************************************************************/
508 /* s e n d E r r */
509 /******************************************************************************/
510 
511 int XrdXrootdAdmin::sendErr(int rc, const char *act, const char *msg)
512 {
513  const char *fmt = "<resp id=\"%s\"><rc>%d</rc><msg>%s %s</msg></resp>\n";
514  char buff[1024];
515  int blen;
516 
517  blen = snprintf(buff, sizeof(buff)-1, fmt, reqID, rc, act, msg);
518  buff[sizeof(buff)-1] = '\0';
519 
520  return Stream.Put(buff, blen);
521 }
522 
523 /******************************************************************************/
524 /* s e n d O K */
525 /******************************************************************************/
526 
527 int XrdXrootdAdmin::sendOK(int sent)
528 {
529  const char *fmt = "<resp id=\"%s\"><rc>0</rc><num>%d</num></resp>\n";
530  char buff[1024];
531  int blen;
532 
533  blen = snprintf(buff, sizeof(buff)-1, fmt, reqID, sent);
534  buff[sizeof(buff)-1] = '\0';
535 
536  return Stream.Put(buff, blen);
537 }
538 
539 /******************************************************************************/
540 /* s e n d R e s p */
541 /******************************************************************************/
542 
543 int XrdXrootdAdmin::sendResp(const char *act, XActionCode anum)
544 {
545  XrdLink *lp;
546  const kXR_int32 net4 = htonl(4);
547  int numsent = 0, curr = -1;
548 
549 // Complete the response header
550 //
551  usResp.act = htonl(anum);
552  usResp.len = net4;
553 
554 // Send off the messages
555 //
556  while((lp = XrdLink::Find(curr, &Target)))
557  {TRACE(RSP, "sending " <<lp->ID <<' ' <<act);
558  if (lp->Send((const char *)&usResp, sizeof(usResp))>0) numsent++;
559  }
560 
561 // Now send the response to the admin guy
562 //
563  return sendOK(numsent);
564 }
565 
566 /******************************************************************************/
567 
568 int XrdXrootdAdmin::sendResp(const char *act, XActionCode anum,
569  const char *msg, int msgl)
570 {
571  struct iovec iov[2];
572  XrdLink *lp;
573  int numsent = 0, curr = -1, bytes = sizeof(usResp)+msgl;
574 
575 // Complete the response header
576 //
577  usResp.act = htonl(anum);
578  usResp.len = htonl(msgl+4);
579 
580 // Construct message vector
581 //
582  iov[0].iov_base = (caddr_t)&usResp;
583  iov[0].iov_len = sizeof(usResp);
584  iov[1].iov_base = (caddr_t)msg;
585  iov[1].iov_len = msgl;
586 
587 // Send off the messages
588 //
589  while((lp = XrdLink::Find(curr, &Target)))
590  {TRACE(RSP, "sending " <<lp->ID <<' ' <<act <<' ' <<msg);
591  if (lp->Send(iov, 2, bytes)>0) numsent++;
592  }
593 
594 // Now send the response to the admin guy
595 //
596  return sendOK(numsent);
597 }
598 
599 /******************************************************************************/
600 /* X e q */
601 /******************************************************************************/
602 
603 void XrdXrootdAdmin::Xeq()
604 {
605  const char *epname = "Xeq";
606  int rc;
607  char *request, *tp;
608 
609 // Start receiving requests on this stream
610 // Format: <msgid> <cmd> <args>
611 //
612  rc = 0;
613  while((request = Stream.GetLine()) && !rc)
614  {TRACE(DEBUG, "received admin request: '" <<request <<"'");
615  if ((rc = getreqID())) continue;
616  if ((tp = Stream.GetToken()))
617  { if (!strcmp("cj", tp)) rc = do_Cj();
618  else if (!strcmp("lsc", tp)) rc = do_Lsc();
619  else if (!strcmp("lsd", tp)) rc = do_Lsd();
620  else if (!strcmp("lsj", tp)) rc = do_Lsj();
621  else if (!strcmp("msg", tp)) rc = do_Msg();
622  else {eDest->Emsg(epname, "invalid admin request,", tp);
623  rc = sendErr(4, tp, "is an invalid request.");
624  }
625  }
626  }
627 
628 // The socket disconnected
629 //
630  eDest->Emsg("Admin", "Admin", TraceID, "logged out");
631  return;
632 }
XActionCode
Definition: XProtocol.hh:929
@ kXR_asyncms
Definition: XProtocol.hh:932
#define kXR_PROTOCOLVSTRING
Definition: XProtocol.hh:75
int kXR_int32
Definition: XPtypes.hh:89
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
static XrdSysError eDest(0,"crypto_")
#define close(a)
Definition: XrdPosix.hh:43
#define XrdSecPROTOIDSIZE
Definition: XrdSecEntity.hh:47
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE(act, x)
Definition: XrdTrace.hh:63
void * XrdXrootdLoginAdmin(void *carg)
XrdSysTrace XrdXrootdTrace
void * XrdXrootdInitAdmin(void *carg)
void * Start(XrdNetSocket *AdminSock)
Definition: XrdCmsAdmin.cc:451
void Login(int socknum)
Definition: XrdCmsAdmin.cc:200
void Set(const char *target)
Definition: XrdLinkMatch.cc:69
int Accept(int ms=-1)
Definition: XrdNetSocket.cc:99
char * GetLine()
int AttachIO(int infd, int outfd, int bsz=2047)
int Put(const char *data, const int dlen)
void SetEroute(XrdSysError *eroute)
char * GetToken(int lowcase=0)
XrdOucTList * next
Definition: XrdOucTList.hh:45
char * text
Definition: XrdOucTList.hh:46
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
Definition: XrdSecEntity.hh:67
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * role
Entity's role(s)
Definition: XrdSecEntity.hh:72
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static int Init(XrdSysError *erp, XrdNetSocket *asock)
void Login(int socknum)
void * Start(XrdNetSocket *AdminSock)
static void addJob(const char *jname, XrdXrootdJob *jp)
int Cancel(const char *jkey=0, XrdXrootdResponse *resp=0)
XrdOucTList * List(void)
XrdSecEntity * Client
XrdXrootdMonitor::User Monitor
XrdCmsAdmin Admin