XRootD
Loading...
Searching...
No Matches
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"
40#include "XrdSys/XrdSysError.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
63void *XrdXrootdInitAdmin(void *carg)
64 {XrdXrootdAdmin Admin;
65 return Admin.Start((XrdNetSocket *)carg);
66 }
67
68void *XrdXrootdLoginAdmin(void *carg)
69 {XrdXrootdAdmin *Admin = new XrdXrootdAdmin();
70 Admin->Login(*(int *)carg);
71 delete Admin;
72 return (void *)0;
73 }
74
75/******************************************************************************/
76/* a d d J o b */
77/******************************************************************************/
78
79void 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
111void 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
172int 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
227int 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
252int 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
282int 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
366int 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
417int 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
435int 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
457char *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
469int 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
492int 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
511int 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
527int 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
543int 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
568int 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
603void 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)
XrdOucTrace * XrdXrootdTrace
#define close(a)
Definition XrdPosix.hh:43
#define XrdSecPROTOIDSIZE
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE(act, x)
Definition XrdTrace.hh:63
void * XrdXrootdLoginAdmin(void *carg)
void * XrdXrootdInitAdmin(void *carg)
void * Start(XrdNetSocket *AdminSock)
void Login(int socknum)
int Accept(int ms=-1)
char * GetToken(int lowcase=0)
XrdOucTList * next
char * vorg
Entity's virtual organization(s)
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
char * name
Entity's name.
char * role
Entity's role(s)
char * host
Entity's host name dnr dependent.
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
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)
XrdXrootdMonitor::User Monitor