XrdXrootdXeq.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                       X r d X r o o t d X e q . c c                        */
00004 /*                                                                            */
00005 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00007 /*              DE-AC03-76-SFO0515 with the Department of Energy              */
00008 /******************************************************************************/
00009 
00010 #include <stdio.h>
00011 
00012 #include "XrdSfs/XrdSfsInterface.hh"
00013 #include "XrdSys/XrdSysError.hh"
00014 #include "XrdSys/XrdSysPlatform.hh"
00015 #include "XrdSys/XrdSysTimer.hh"
00016 #include "XrdOuc/XrdOucReqID.hh"
00017 #include "XrdOuc/XrdOucTList.hh"
00018 #include "XrdOuc/XrdOucStream.hh"
00019 #include "XrdOuc/XrdOucTokenizer.hh"
00020 #include "XrdSec/XrdSecInterface.hh"
00021 #include "Xrd/XrdBuffer.hh"
00022 #include "Xrd/XrdLink.hh"
00023 #include "XrdXrootd/XrdXrootdAio.hh"
00024 #include "XrdXrootd/XrdXrootdCallBack.hh"
00025 #include "XrdXrootd/XrdXrootdFile.hh"
00026 #include "XrdXrootd/XrdXrootdFileLock.hh"
00027 #include "XrdXrootd/XrdXrootdJob.hh"
00028 #include "XrdXrootd/XrdXrootdMonitor.hh"
00029 #include "XrdXrootd/XrdXrootdPio.hh"
00030 #include "XrdXrootd/XrdXrootdPrepare.hh"
00031 #include "XrdXrootd/XrdXrootdProtocol.hh"
00032 #include "XrdXrootd/XrdXrootdStats.hh"
00033 #include "XrdXrootd/XrdXrootdTrace.hh"
00034 #include "XrdXrootd/XrdXrootdXPath.hh"
00035   
00036 /******************************************************************************/
00037 /*                               G l o b a l s                                */
00038 /******************************************************************************/
00039 
00040 extern XrdOucTrace *XrdXrootdTrace;
00041 
00042 /******************************************************************************/
00043 /*                      L o c a l   S t r u c t u r e s                       */
00044 /******************************************************************************/
00045   
00046 struct XrdXrootdFHandle
00047        {kXR_int32 handle;
00048 
00049         void Set(kXR_char *ch)
00050             {memcpy((void *)&handle, (const void *)ch, sizeof(handle));}
00051         XrdXrootdFHandle() {}
00052         XrdXrootdFHandle(kXR_char *ch) {Set(ch);}
00053        ~XrdXrootdFHandle() {}
00054        };
00055 
00056 struct XrdXrootdSessID
00057        {unsigned int       Sid;
00058                  int       Pid;
00059                  int       FD;
00060         unsigned int       Inst;
00061 
00062         XrdXrootdSessID() {}
00063        ~XrdXrootdSessID() {}
00064        };
00065 
00066 /******************************************************************************/
00067 /*                         L o c a l   D e f i n e s                          */
00068 /******************************************************************************/
00069 
00070 #define CRED (const XrdSecEntity *)Client
00071 
00072 #define TRACELINK Link
00073 
00074 #define UPSTATS(x) SI->statsMutex.Lock(); SI->x++; SI->statsMutex.UnLock()
00075  
00076 /******************************************************************************/
00077 /*                              d o _ A d m i n                               */
00078 /******************************************************************************/
00079   
00080 int XrdXrootdProtocol::do_Admin()
00081 {
00082    return Response.Send(kXR_Unsupported, "admin request is not supported");
00083 }
00084   
00085 /******************************************************************************/
00086 /*                               d o _ A u t h                                */
00087 /******************************************************************************/
00088   
00089 int XrdXrootdProtocol::do_Auth()
00090 {
00091     struct sockaddr netaddr;
00092     XrdSecCredentials cred;
00093     XrdSecParameters *parm = 0;
00094     XrdOucErrInfo     eMsg;
00095     const char *eText;
00096     int rc, n;
00097 
00098 // Ignore authenticate requests if security turned off
00099 //
00100    if (!CIA) return Response.Send();
00101    cred.size   = Request.header.dlen;
00102    cred.buffer = argp->buff;
00103 
00104 // If we have no auth protocol or the current protocol is being changed by the
00105 // client (the client can do so at any time), try to get it. Track number of
00106 // times we got a protocol object as the read count (we will zero it out later).
00107 // The credtype change check is always done. While the credtype is consistent,
00108 // not all protocols provided this information in the past. So, old clients will
00109 // not necessarily be able to switch protocols mid-stream.
00110 //
00111    if (!AuthProt
00112    ||  strncmp(Entity.prot, (const char *)Request.auth.credtype,
00113                                    sizeof(Request.auth.credtype)))
00114       {if (AuthProt) AuthProt->Delete();
00115        strncpy(Entity.prot, (const char *)Request.auth.credtype,
00116                                    sizeof(Request.auth.credtype));
00117        Link->Name(&netaddr);
00118        if (!(AuthProt = CIA->getProtocol(Link->Host(),netaddr,&cred,&eMsg)))
00119           {eText = eMsg.getErrText(rc);
00120            eDest.Emsg("Xeq", "User authentication failed;", eText);
00121            return Response.Send(kXR_NotAuthorized, eText);
00122           }
00123        AuthProt->Entity.tident = Link->ID; numReads++;
00124       }
00125 
00126 // Now try to authenticate the client using the current protocol
00127 //
00128    if (!(rc = AuthProt->Authenticate(&cred, &parm, &eMsg)))
00129       {const char *msg = (Status & XRD_ADMINUSER ? "admin login as"
00130                                                  : "login as");
00131        rc = Response.Send(); Status &= ~XRD_NEED_AUTH;
00132        Client = &AuthProt->Entity; numReads = 0; strcpy(Entity.prot, "host");
00133        if (Client->name) 
00134           eDest.Log(SYS_LOG_01, "Xeq", Link->ID, msg, Client->name);
00135           else
00136           eDest.Log(SYS_LOG_01, "Xeq", Link->ID, msg, "nobody");
00137        return rc;
00138       }
00139 
00140 // If we need to continue authentication, tell the client as much
00141 //
00142    if (rc > 0)
00143       {TRACEP(LOGIN, "more auth requested; sz=" <<(parm ? parm->size : 0));
00144        if (parm) {rc = Response.Send(kXR_authmore, parm->buffer, parm->size);
00145                   delete parm;
00146                   return rc;
00147                  }
00148        eDest.Emsg("Xeq", "Security requested additional auth w/o parms!");
00149        return Response.Send(kXR_ServerError,"invalid authentication exchange");
00150       }
00151 
00152 // Authentication failed. We will delete the authentication object and zero
00153 // out the pointer. We can do this without any locks because this section is
00154 // single threaded relative to a connection. To prevent guessing attacks, we
00155 // wait a variable amount of time if there have been 3 or more tries.
00156 //
00157    if (AuthProt) {AuthProt->Delete(); AuthProt = 0;}
00158    if ((n = numReads - 2) > 0) XrdSysTimer::Snooze(n > 5 ? 5 : n);
00159 
00160 // We got an error, bail out.
00161 //
00162    eText = eMsg.getErrText(rc);
00163    eDest.Emsg("Xeq", "User authentication failed;", eText);
00164    return Response.Send(kXR_NotAuthorized, eText);
00165 }
00166 
00167 /******************************************************************************/
00168 /*                               d o _ B i n d                                */
00169 /******************************************************************************/
00170   
00171 int XrdXrootdProtocol::do_Bind()
00172 {
00173    XrdXrootdSessID *sp = (XrdXrootdSessID *)Request.bind.sessid;
00174    XrdXrootdProtocol *pp;
00175    XrdLink *lp;
00176    int i, pPid, rc;
00177    char buff[64], *cp, *dp;
00178 
00179 // Update misc stats count
00180 //
00181    UPSTATS(miscCnt);
00182 
00183 // Find the link we are to bind to
00184 //
00185    if (sp->FD <= 0 || !(lp = XrdLink::fd2link(sp->FD, sp->Inst)))
00186       return Response.Send(kXR_NotFound, "session not found");
00187 
00188 // The link may have escaped so we need to hold this link and try again
00189 //
00190    lp->Hold(1);
00191    if (lp != XrdLink::fd2link(sp->FD, sp->Inst))
00192       {lp->Hold(0);
00193        return Response.Send(kXR_NotFound, "session just closed");
00194       }
00195 
00196 // Get the protocol associated with the link
00197 //
00198    if (!(pp=dynamic_cast<XrdXrootdProtocol *>(lp->getProtocol()))||lp != pp->Link)
00199       {lp->Hold(0);
00200        return Response.Send(kXR_ArgInvalid, "session protocol not xroot");
00201       }
00202 
00203 // Verify that the parent protocol is fully logged in
00204 //
00205    if (!(pp->Status & XRD_LOGGEDIN) || (pp->Status & XRD_NEED_AUTH))
00206       {lp->Hold(0);
00207        return Response.Send(kXR_ArgInvalid, "session not logged in");
00208       }
00209 
00210 // Verify that the bind is valid for the requestor
00211 //
00212    if (sp->Pid != myPID || sp->Sid != pp->mySID)
00213       {lp->Hold(0);
00214        return Response.Send(kXR_ArgInvalid, "invalid session ID");
00215       }
00216 
00217 // For now, verify that the request is comming from the same host
00218 //
00219    if (strcmp(Link->Host(), lp->Host()))
00220       {lp->Hold(0);
00221        return Response.Send(kXR_NotAuthorized, "cross-host bind not allowed");
00222       }
00223 
00224 // Find a slot for this path in parent protocol
00225 //
00226    for (i = 1; i < maxStreams && pp->Stream[i]; i++) {}
00227    if (i >= maxStreams)
00228       {lp->Hold(0);
00229        return Response.Send(kXR_NoMemory, "bind limit exceeded");
00230       }
00231 
00232 // Link this protocol to the parent
00233 //
00234    pp->Stream[i] = this;
00235    Stream[0]     = pp;
00236    pp->isBound   = 1;
00237    PathID        = i;
00238    sprintf(buff, "FD %d#%d bound", Link->FDnum(), i);
00239    eDest.Log(SYS_LOG_01, "Xeq", buff, lp->ID);
00240 
00241 // Construct a login name for this bind session
00242 //
00243    cp = strdup(lp->ID);
00244    if ( (dp = rindex(cp, '@'))) *dp = '\0';
00245    if (!(dp = rindex(cp, '.'))) pPid = 0;
00246       else {*dp++ = '\0'; pPid = strtol(dp, (char **)NULL, 10);}
00247    Link->setID(cp, pPid);
00248    free(cp);
00249    CapVer = pp->CapVer;
00250    Status = XRD_BOUNDPATH;
00251 
00252 // Get the required number of parallel I/O objects
00253 //
00254    pioFree = XrdXrootdPio::Alloc(maxPio);
00255 
00256 // There are no errors possible at this point unless the response fails
00257 //
00258    buff[0] = static_cast<char>(i);
00259    if (!(rc = Response.Send(kXR_ok, buff, 1))) rc = -EINPROGRESS;
00260 
00261 // Return but keep the link disabled
00262 //
00263    lp->Hold(0);
00264    return rc;
00265 }
00266 
00267 /******************************************************************************/
00268 /*                              d o _ c h m o d                               */
00269 /******************************************************************************/
00270   
00271 int XrdXrootdProtocol::do_Chmod()
00272 {
00273    int mode, rc;
00274    const char *opaque;
00275    XrdOucErrInfo myError(Link->ID);
00276 
00277 // Check for static routing
00278 //
00279    if (Route[RD_chmod].Port) 
00280       return Response.Send(kXR_redirect,Route[RD_chmod].Port,Route[RD_chmod].Host);
00281 
00282 // Unmarshall the data
00283 //
00284    mode = mapMode((int)ntohs(Request.chmod.mode));
00285    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Modifying", argp->buff);
00286    if (!Squash(argp->buff))          return vpEmsg("Modifying", argp->buff);
00287 
00288 // Preform the actual function
00289 //
00290    rc = osFS->chmod(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
00291    TRACEP(FS, "chmod rc=" <<rc <<" mode=" <<std::oct <<mode <<std::dec <<' ' <<argp->buff);
00292    if (SFS_OK == rc) return Response.Send();
00293 
00294 // An error occured
00295 //
00296    return fsError(rc, myError);
00297 }
00298 
00299 /******************************************************************************/
00300 /*                              d o _ C K s u m                               */
00301 /******************************************************************************/
00302   
00303 int XrdXrootdProtocol::do_CKsum(int canit)
00304 {
00305    const char *opaque;
00306    char *args[3];
00307 
00308 // Check if we support this operation
00309 //
00310    if (!JobCKS)
00311       return Response.Send(kXR_Unsupported, "query chksum is not supported");
00312 
00313 // Prescreen the path
00314 //
00315    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Check summing", argp->buff);
00316    if (!Squash(argp->buff))          return vpEmsg("Check summing", argp->buff);
00317 
00318 // If this is a cancel request, do it now
00319 //
00320    if (canit)
00321       {JobCKS->Cancel(argp->buff, &Response);
00322        return Response.Send();
00323       }
00324 
00325 // Construct the argument list
00326 //
00327    args[0] = JobCKT;
00328    args[1] = argp->buff;
00329    args[2] = 0;
00330 
00331 // Preform the actual function
00332 //
00333    return JobCKS->Schedule(argp->buff, (const char **)args, &Response,
00334                   ((CapVer & kXR_vermask) >= kXR_ver002 ? 0 : JOB_Sync));
00335 }
00336 
00337 /******************************************************************************/
00338 /*                              d o _ C l o s e                               */
00339 /******************************************************************************/
00340   
00341 int XrdXrootdProtocol::do_Close()
00342 {
00343    XrdXrootdFile *fp;
00344    XrdXrootdFHandle fh(Request.close.fhandle);
00345    int rc;
00346 
00347 // Keep statistics
00348 //
00349    UPSTATS(miscCnt);
00350 
00351 // Find the file object
00352 //
00353    if (!FTab || !(fp = FTab->Get(fh.handle)))
00354       return Response.Send(kXR_FileNotOpen, 
00355                           "close does not refer to an open file");
00356 
00357 // Serialize the link to make sure that any in-flight operations on this handle
00358 // have completed (async mode or parallel streams)
00359 //
00360    Link->Serialize();
00361 
00362 // If we are monitoring, insert a close entry
00363 //
00364    if (monFILE && Monitor) Monitor->Close(fp->FileID,fp->readCnt,fp->writeCnt);
00365 
00366 // Do an explicit close of the file here; reflecting any errors
00367 //
00368    rc = fp->XrdSfsp->close();
00369    TRACEP(FS, "close rc=" <<rc <<" fh=" <<fh.handle);
00370    if (SFS_OK != rc)
00371       return Response.Send(kXR_FSError, fp->XrdSfsp->error.getErrText());
00372 
00373 // Delete the file from the file table; this will unlock/close the file
00374 //
00375    FTab->Del(fh.handle);
00376    numFiles--;
00377    return Response.Send();
00378 }
00379 
00380 /******************************************************************************/
00381 /*                            d o _ D i r l i s t                             */
00382 /******************************************************************************/
00383   
00384 int XrdXrootdProtocol::do_Dirlist()
00385 {
00386    int bleft, rc = 0, dlen, cnt = 0;
00387    char *buff, ebuff[4096];
00388    const char *opaque, *dname;
00389    XrdSfsDirectory *dp;
00390 
00391 // Check for static routing
00392 //
00393    if (Route[RD_dirlist].Port) 
00394       return Response.Send(kXR_redirect,Route[RD_dirlist].Port,Route[RD_dirlist].Host);
00395 
00396 // Prescreen the path
00397 //
00398    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Listing", argp->buff);
00399    if (!Squash(argp->buff))          return vpEmsg("Listing", argp->buff);
00400 
00401 // Get a directory object
00402 //
00403    if (!(dp = osFS->newDir(Link->ID)))
00404       {snprintf(ebuff,sizeof(ebuff)-1,"Insufficient memory to open %s",argp->buff);
00405        eDest.Emsg("Xeq", ebuff);
00406        return Response.Send(kXR_NoMemory, ebuff);
00407       }
00408 
00409 // First open the directory
00410 //
00411    if ((rc = dp->open(argp->buff, CRED, opaque)))
00412       {rc = fsError(rc, dp->error); delete dp; return rc;}
00413 
00414 // Start retreiving each entry and place in a local buffer with a trailing new
00415 // line character (the last entry will have a null byte). If we cannot fit a
00416 // full entry in the buffer, send what we have with an OKSOFAR and continue.
00417 // This code depends on the fact that a directory entry will never be longer
00418 // than sizeof( ebuff)-1; otherwise, an infinite loop will result. No errors
00419 // are allowed to be reflected at this point.
00420 //
00421   dname = 0;
00422   do {buff = ebuff; bleft = sizeof(ebuff);
00423       while(dname || (dname = dp->nextEntry()))
00424            {dlen = strlen(dname);
00425             if (dlen > 2 || dname[0] != '.' || (dlen == 2 && dname[1] != '.'))
00426                {if ((bleft -= (dlen+1)) < 0) break;
00427                 strcpy(buff, dname); buff += dlen; *buff = '\n'; buff++; cnt++;
00428                }
00429             dname = 0;
00430            }
00431        if (dname) rc = Response.Send(kXR_oksofar, ebuff, buff-ebuff);
00432      } while(!rc && dname);
00433 
00434 // Send the ending packet if we actually have one to send
00435 //
00436    if (!rc) 
00437       {if (ebuff == buff) rc = Response.Send();
00438           else {*(buff-1) = '\0';
00439                 rc = Response.Send((void *)ebuff, buff-ebuff);
00440                }
00441       }
00442 
00443 // Close the directory
00444 //
00445    dp->close();
00446    delete dp;
00447    if (!rc) {TRACEP(FS, "dirlist entries=" <<cnt <<" path=" <<argp->buff);}
00448    return rc;
00449 }
00450 
00451 /******************************************************************************/
00452 /*                            d o _ E n d s e s s                             */
00453 /******************************************************************************/
00454   
00455 int XrdXrootdProtocol::do_Endsess()
00456 {
00457    XrdXrootdSessID *sp, sessID;
00458    int rc;
00459 
00460 // Update misc stats count
00461 //
00462    UPSTATS(miscCnt);
00463 
00464 // Extract out the FD and Instance from the session ID
00465 //
00466    sp = (XrdXrootdSessID *)Request.endsess.sessid;
00467    memcpy((void *)&sessID.Pid,  &sp->Pid,  sizeof(sessID.Pid));
00468    memcpy((void *)&sessID.FD,   &sp->FD,   sizeof(sessID.FD));
00469    memcpy((void *)&sessID.Inst, &sp->Inst, sizeof(sessID.Inst));
00470 
00471 // Trace this request
00472 //
00473    TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst);
00474 
00475 // If this session id does not refer to us, ignore the request
00476 //
00477    if (sessID.Pid != myPID) return Response.Send();
00478 
00479 // Terminate the indicated session, if possible. This could also be a self-termination.
00480 //
00481    if ((sessID.FD == 0 && sessID.Inst == 0) 
00482    ||  !(rc = Link->Terminate(Link, sessID.FD, sessID.Inst))) return -1;
00483 
00484 // Trace this request
00485 //
00486    TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst
00487           <<" rc=" <<rc <<" (" <<strerror(rc < 0 ? -rc : EAGAIN) <<")");
00488 
00489 // Return result
00490 //
00491    if (rc >  0)
00492       return (rc = Response.Send(kXR_wait, rc, "session still active")) ? rc:1;
00493 
00494    if (rc == -EACCES)return Response.Send(kXR_NotAuthorized, "not session owner");
00495    if (rc == -ESRCH) return Response.Send(kXR_NotFound, "session not found");
00496    if (rc == -ETIME) return Response.Send(kXR_Cancelled,"session not ended");
00497 
00498    return Response.Send();
00499 }
00500 
00501 /******************************************************************************/
00502 /*                            d o   G e t f i l e                             */
00503 /******************************************************************************/
00504   
00505 int XrdXrootdProtocol::do_Getfile()
00506 {
00507    int gopts, buffsz;
00508 
00509 // Keep Statistics
00510 //
00511    UPSTATS(getfCnt);
00512 
00513 // Unmarshall the data
00514 //
00515    gopts  = int(ntohl(Request.getfile.options));
00516    buffsz = int(ntohl(Request.getfile.buffsz));
00517 
00518    return Response.Send(kXR_Unsupported, "getfile request is not supported");
00519 }
00520 
00521 /******************************************************************************/
00522 /*                             d o _ L o c a t e                              */
00523 /******************************************************************************/
00524 
00525 int XrdXrootdProtocol::do_Locate()
00526 {
00527    static XrdXrootdCallBack locCB("locate");
00528    int rc, opts, fsctl_cmd = SFS_FSCTL_LOCATE;
00529    const char *opaque;
00530    char *Path, *fn = argp->buff, opt[8], *op=opt;
00531    XrdOucErrInfo myError(Link->ID, &locCB, ReqID.getID());
00532 
00533 // Unmarshall the data
00534 //
00535    opts = (int)ntohs(Request.locate.options);
00536 
00537 // Map the options
00538 //
00539    if (opts & kXR_nowait)  {fsctl_cmd |= SFS_O_NOWAIT; *op++ = 'i';}
00540    if (opts & kXR_refresh) {fsctl_cmd |= SFS_O_RESET;  *op++ = 's';}
00541    *op = '\0';
00542    TRACEP(FS, "locate " <<opt <<' ' <<fn);
00543 
00544 // Check for static routing
00545 //
00546    if (Route[RD_locate].Port)
00547       return Response.Send(kXR_redirect, Route[RD_locate].Port,
00548                                          Route[RD_locate].Host);
00549 
00550 // Check if this is a non-specific locate
00551 //
00552         if (*fn != '*') Path = fn;
00553    else if (*(fn+1))    Path = fn+1;
00554    else                {Path = 0; 
00555                         fn = XPList.Next()->Path();
00556                         fsctl_cmd |= SFS_O_TRUNC;
00557                        }
00558 
00559 // Prescreen the path
00560 //
00561    if (Path)
00562       {if (rpCheck(Path, &opaque)) return rpEmsg("Locating", Path);
00563        if (!Squash(Path))          return vpEmsg("Locating", Path);
00564       }
00565 
00566 // Preform the actual function
00567 //
00568    rc = osFS->fsctl(fsctl_cmd, fn, myError, CRED);
00569    TRACEP(FS, "rc=" <<rc <<" locate " <<fn);
00570    return fsError(rc, myError);
00571 }
00572   
00573 /******************************************************************************/
00574 /*                              d o _ L o g i n                               */
00575 /******************************************************************************/
00576   
00577 int XrdXrootdProtocol::do_Login()
00578 {
00579    static XrdSysMutex sessMutex;
00580    static unsigned int Sid = 0;
00581    XrdXrootdSessID sessID;
00582    int i, pid, rc, sendSID = 0;
00583    char uname[sizeof(Request.login.username)+1];
00584 
00585 // Keep Statistics
00586 //
00587    UPSTATS(miscCnt);
00588 
00589 // Unmarshall the data
00590 //
00591    pid = (int)ntohl(Request.login.pid);
00592    for (i = 0; i < (int)sizeof(Request.login.username); i++)
00593       {if (Request.login.username[i] == '\0' ||
00594            Request.login.username[i] == ' ') break;
00595        uname[i] = Request.login.username[i];
00596       }
00597    uname[i] = '\0';
00598 
00599 // Make sure the user is not already logged in
00600 //
00601    if (Status) return Response.Send(kXR_InvalidRequest,
00602                                     "duplicate login; already logged in");
00603 
00604 // Establish the ID for this link
00605 //
00606    Link->setID(uname, pid);
00607    CapVer = Request.login.capver[0];
00608 
00609 // Establish the session ID if the client can handle it (protocol version > 0)
00610 //
00611    if (CapVer && kXR_vermask)
00612       {sessID.FD   = Link->FDnum();
00613        sessID.Inst = Link->Inst();
00614        sessID.Pid  = myPID;
00615        sessMutex.Lock(); mySID = ++Sid; sessMutex.UnLock();
00616        sessID.Sid  = mySID;
00617        sendSID = 1;
00618       }
00619 
00620 // Check if this is an admin login
00621 //
00622    if (*(Request.login.role) & (kXR_char)kXR_useradmin)
00623       Status = XRD_ADMINUSER;
00624 
00625 // Get the security token for this link. We will either get a token, a null
00626 // string indicating host-only authentication, or a null indicating no
00627 // authentication. We can then optimize of each case.
00628 //
00629    if (CIA)
00630       {const char *pp=CIA->getParms(i, Link->Host());
00631        if (pp && i ) {if (!sendSID) rc = Response.Send((void *)pp, i);
00632                          else {struct iovec iov[3];
00633                                iov[1].iov_base = (char *)&sessID;
00634                                iov[1].iov_len  = sizeof(sessID);
00635                                iov[2].iov_base = (char *)pp;
00636                                iov[2].iov_len  = i;
00637                                rc = Response.Send(iov,3,int(i+sizeof(sessID)));
00638                               }
00639                       Status = (XRD_LOGGEDIN | XRD_NEED_AUTH);
00640                      }
00641           else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
00642                               : Response.Send());
00643                 Status = XRD_LOGGEDIN;
00644                 if (pp) {Entity.tident = Link->ID; Client = &Entity;}
00645                }
00646       }
00647       else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
00648                           : Response.Send());
00649             Status = XRD_LOGGEDIN;
00650            }
00651 
00652 // Allocate a monitoring object, if needed for this connection
00653 //
00654    if ((Monitor = XrdXrootdMonitor::Alloc()))
00655       {monFILE = XrdXrootdMonitor::monFILE;
00656        monIO   = XrdXrootdMonitor::monIO;
00657        if (XrdXrootdMonitor::monUSER)
00658           monUID = XrdXrootdMonitor::Map(XROOTD_MON_MAPUSER, Link->ID, 0);
00659       }
00660 
00661 // Complete the rquestID object
00662 //
00663    ReqID.setID(Request.header.streamid, Link->FDnum(), Link->Inst());
00664 
00665 // Document this login
00666 //
00667    if (!(Status & XRD_NEED_AUTH))
00668       eDest.Log(SYS_LOG_01, "Xeq", Link->ID, (Status & XRD_ADMINUSER
00669                             ? "admin login" : "login"));
00670    return rc;
00671 }
00672 
00673 /******************************************************************************/
00674 /*                              d o _ M k d i r                               */
00675 /******************************************************************************/
00676   
00677 int XrdXrootdProtocol::do_Mkdir()
00678 {
00679    int mode, rc;
00680    const char *opaque;
00681    XrdOucErrInfo myError(Link->ID);
00682 
00683 // Check for static routing
00684 //
00685    if (Route[RD_mkdir].Port) 
00686       return Response.Send(kXR_redirect,Route[RD_mkdir].Port,Route[RD_mkdir].Host);
00687 
00688 // Unmarshall the data
00689 //
00690    mode = mapMode((int)ntohs(Request.mkdir.mode)) | S_IRWXU;
00691    if (Request.mkdir.options[0] & static_cast<unsigned char>(kXR_mkdirpath))
00692       mode |= SFS_O_MKPTH;
00693    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Creating", argp->buff);
00694    if (!Squash(argp->buff))          return vpEmsg("Creating", argp->buff);
00695 
00696 // Preform the actual function
00697 //
00698    rc = osFS->mkdir(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
00699    TRACEP(FS, "rc=" <<rc <<" mkdir " <<std::oct <<mode <<std::dec <<' ' <<argp->buff);
00700    if (SFS_OK == rc) return Response.Send();
00701 
00702 // An error occured
00703 //
00704    return fsError(rc, myError);
00705 }
00706 
00707 /******************************************************************************/
00708 /*                                 d o _ M v                                  */
00709 /******************************************************************************/
00710   
00711 int XrdXrootdProtocol::do_Mv()
00712 {
00713    int rc;
00714    const char *Opaque, *Npaque;
00715    char *oldp, *newp;
00716    XrdOucErrInfo myError(Link->ID);
00717 
00718 // Check for static routing
00719 //
00720    if (Route[RD_mv].Port) 
00721       return Response.Send(kXR_redirect,Route[RD_mv].Port,Route[RD_mv].Host);
00722 
00723 // Find the space separator between the old and new paths
00724 //
00725    oldp = newp = argp->buff;
00726    while(*newp && *newp != ' ') newp++;
00727    if (*newp) {*newp = '\0'; newp++;
00728                while(*newp && *newp == ' ') newp++;
00729               }
00730 
00731 // Get rid of relative paths and multiple slashes
00732 //
00733    if (rpCheck(oldp, &Opaque)) return rpEmsg("Renaming",    oldp);
00734    if (rpCheck(newp, &Npaque)) return rpEmsg("Renaming to", newp);
00735    if (!Squash(oldp))          return vpEmsg("Renaming",    oldp);
00736    if (!Squash(newp))          return vpEmsg("Renaming to", newp);
00737 
00738 // Check if new path actually specified here
00739 //
00740    if (*newp == '\0')
00741       Response.Send(kXR_ArgMissing, "new path specfied for mv");
00742 
00743 // Preform the actual function
00744 //
00745    rc = osFS->rename(oldp, newp, myError, CRED, Opaque, Npaque);
00746    TRACEP(FS, "rc=" <<rc <<" mv " <<oldp <<' ' <<newp);
00747    if (SFS_OK == rc) return Response.Send();
00748 
00749 // An error occured
00750 //
00751    return fsError(rc, myError);
00752 }
00753 
00754 /******************************************************************************/
00755 /*                            d o _ O f f l o a d                             */
00756 /******************************************************************************/
00757 
00758 int XrdXrootdProtocol::do_Offload(int pathID, int isWrite)
00759 {
00760    XrdSysSemaphore isAvail(0);
00761    XrdXrootdProtocol *pp;
00762    XrdXrootdPio      *pioP;
00763    kXR_char streamID[2];
00764 
00765 // Verify that the path actually exists
00766 //
00767    if (pathID >= maxStreams || !(pp = Stream[pathID]))
00768       return Response.Send(kXR_ArgInvalid, "invalid path ID");
00769 
00770 // Verify that this path is still functional
00771 //
00772    pp->streamMutex.Lock();
00773    if (pp->isDead || pp->isNOP)
00774       {pp->streamMutex.UnLock();
00775        return Response.Send(kXR_ArgInvalid, 
00776        (pp->isDead ? "path ID is not functional"
00777                    : "path ID is not connected"));
00778       }
00779 
00780 // Grab the stream ID
00781 //
00782    Response.StreamID(streamID);
00783 
00784 // Try to schedule this operation. In order to maximize the I/O overlap, we
00785 // will wait until the stream gets control and will have a chance to start
00786 // reading from the device or from the network.
00787 //
00788    do{if (!pp->isActive)
00789          {pp->myFile   = myFile;
00790           pp->myOffset = myOffset;
00791           pp->myIOLen  = myIOLen;
00792           pp->myBlen   = 0;
00793           pp->doWrite  = static_cast<char>(isWrite);
00794           pp->doWriteC = 0;
00795           pp->Resume   = &XrdXrootdProtocol::do_OffloadIO;
00796           pp->isActive = 1;
00797           pp->reTry    = &isAvail;
00798           pp->Response.Set(streamID);
00799           pp->streamMutex.UnLock();
00800           Link->setRef(1);
00801           Sched->Schedule((XrdJob *)(pp->Link));
00802           isAvail.Wait();
00803           return 0;
00804          }
00805 
00806       if ((pioP = pp->pioFree)) break;
00807       pp->reTry = &isAvail;
00808       pp->streamMutex.UnLock();
00809       TRACEP(FS, (isWrite ? 'w' : 'r') <<" busy path " <<pathID <<" offs=" <<myOffset);
00810       isAvail.Wait();
00811       TRACEP(FS, (isWrite ? 'w' : 'r') <<" free path " <<pathID <<" offs=" <<myOffset);
00812       pp->streamMutex.Lock();
00813       if (pp->isNOP)
00814          {pp->streamMutex.UnLock();
00815           return Response.Send(kXR_ArgInvalid, "path ID is not connected");
00816          }
00817       } while(1);
00818 
00819 // Fill out the queue entry and add it to the queue
00820 //
00821    pp->pioFree = pioP->Next; pioP->Next = 0;
00822    pioP->Set(myFile, myOffset, myIOLen, streamID, static_cast<char>(isWrite));
00823    if (pp->pioLast) pp->pioLast->Next = pioP;
00824       else          pp->pioFirst      = pioP;
00825    pp->pioLast = pioP;
00826    pp->streamMutex.UnLock();
00827    return 0;
00828 }
00829 
00830 /******************************************************************************/
00831 /*                          d o _ O f f l o a d I O                           */
00832 /******************************************************************************/
00833 
00834 int XrdXrootdProtocol::do_OffloadIO()
00835 {
00836    XrdSysSemaphore *sesSem;
00837    XrdXrootdPio    *pioP;
00838    int rc;
00839 
00840 // Entry implies that we just got scheduled and are marked as active. Hence
00841 // we need to post the session thread so that it can pick up the next request.
00842 // We can manipulate the semaphore pointer without a lock as the only other
00843 // thread that can manipulate the pointer is the waiting session thread.
00844 //
00845    if (!doWriteC && (sesSem = reTry)) {reTry = 0; sesSem->Post();}
00846   
00847 // Perform all I/O operations on a parallel stream (suppress async I/O).
00848 //
00849    do {if (!doWrite) rc = do_ReadAll(0);
00850           else if ( (rc = (doWriteC ? do_WriteCont() : do_WriteAll()) ) > 0)
00851                   {Resume = &XrdXrootdProtocol::do_OffloadIO;
00852                    doWriteC = 1;
00853                    return rc;
00854                   }
00855        streamMutex.Lock();
00856        if (rc || !(pioP = pioFirst)) break;
00857        if (!(pioFirst = pioP->Next)) pioLast = 0;
00858        myFile   = pioP->myFile;
00859        myOffset = pioP->myOffset;
00860        myIOLen  = pioP->myIOLen;
00861        doWrite  = pioP->isWrite;
00862        doWriteC = 0;
00863        Response.Set(pioP->StreamID);
00864        pioP->Next = pioFree; pioFree = pioP;
00865        if (reTry) {reTry->Post(); reTry = 0;}
00866        streamMutex.UnLock();
00867       } while(1);
00868 
00869 // There are no pending operations or the link died
00870 //
00871    if (rc) isNOP = 1;
00872    isActive = 0;
00873    Stream[0]->Link->setRef(-1);
00874    if (reTry) {reTry->Post(); reTry = 0;}
00875    streamMutex.UnLock();
00876    return -EINPROGRESS;
00877 }
00878 
00879 /******************************************************************************/
00880 /*                               d o _ O p e n                                */
00881 /******************************************************************************/
00882   
00883 int XrdXrootdProtocol::do_Open()
00884 {
00885    static XrdXrootdCallBack openCB("open file");
00886    int fhandle;
00887    int rc, mode, opts, openopts, mkpath = 0, doforce = 0, compchk = 0;
00888    int popt, retStat = 0;
00889    const char *opaque;
00890    char usage, ebuff[2048];
00891    char *fn = argp->buff, opt[16], *op=opt, isAsync = '\0';
00892    XrdSfsFile *fp;
00893    XrdXrootdFile *xp;
00894    struct stat statbuf;
00895    struct ServerResponseBody_Open myResp;
00896    int resplen = sizeof(myResp.fhandle);
00897    struct iovec IOResp[3];  // Note that IOResp[0] is completed by Response
00898 
00899 // Keep Statistics
00900 //
00901    UPSTATS(openCnt);
00902 
00903 // Unmarshall the data
00904 //
00905    mode = (int)ntohs(Request.open.mode);
00906    opts = (int)ntohs(Request.open.options);
00907 
00908 // Map the mode and options
00909 //
00910    mode = mapMode(mode) | S_IRUSR | S_IWUSR; usage = 'r';
00911         if (opts & kXR_open_read)  
00912            {openopts  = SFS_O_RDONLY;  *op++ = 'r';}
00913    else if (opts & kXR_open_updt)   
00914            {openopts  = SFS_O_RDWR;    *op++ = 'u'; usage = 'w';}
00915    else    {openopts  = SFS_O_RDONLY;  *op++ = 'r';}
00916 
00917         if (opts & kXR_new)
00918            {openopts |= SFS_O_CREAT;   *op++ = 'n';
00919             if (opts & kXR_replica)   {*op++ = '+';
00920                                        openopts |= SFS_O_REPLICA;
00921                                       }
00922             if (opts & kXR_mkdir)     {*op++ = 'm'; mkpath = 1;
00923                                        mode |= SFS_O_MKPTH;
00924                                       }
00925            }
00926    else if (opts & kXR_delete)
00927            {openopts  = SFS_O_TRUNC;   *op++ = 'd';
00928             if (opts & kXR_mkdir)     {*op++ = 'm'; mkpath = 1;
00929                                        mode |= SFS_O_MKPTH;
00930                                       }
00931            }
00932    if (opts & kXR_compress)        
00933            {openopts |= SFS_O_RAWIO;   *op++ = 'c'; compchk = 1;}
00934    if (opts & kXR_force)              {*op++ = 'f'; doforce = 1;}
00935    if ((opts & kXR_async || as_force) && !as_noaio)
00936                                       {*op++ = 'a'; isAsync = '1';}
00937    if (opts & kXR_refresh)            {*op++ = 's'; openopts |= SFS_O_RESET;
00938                                        UPSTATS(Refresh);
00939                                       }
00940    if (opts & kXR_retstat)            {*op++ = 't'; retStat = 1;}
00941    if (opts & kXR_posc)               {*op++ = 'p'; openopts |= SFS_O_POSC;}
00942    *op = '\0';
00943    TRACEP(FS, "open " <<opt <<' ' <<fn);
00944 
00945 // Check if opaque data has been provided
00946 //
00947    if (rpCheck(fn, &opaque)) return rpEmsg("Opening", fn);
00948 
00949 // Check if static redirection applies
00950 //
00951    if (Route[RD_open1].Host && (popt = RPList.Validate(fn)))
00952       return Response.Send(kXR_redirect,Route[popt].Port,Route[popt].Host);
00953 
00954 // Validate the path
00955 //
00956    if (!(popt = Squash(fn))) return vpEmsg("Opening", fn);
00957 
00958 // Get a file object
00959 //
00960    if (!(fp = osFS->newFile(Link->ID)))
00961       {snprintf(ebuff, sizeof(ebuff)-1,"Insufficient memory to open %s",fn);
00962        eDest.Emsg("Xeq", ebuff);
00963        return Response.Send(kXR_NoMemory, ebuff);
00964       }
00965 
00966 // The open is elegible for a defered response, indicate we're ok with that
00967 //
00968    fp->error.setErrCB(&openCB, ReqID.getID());
00969 
00970 // Open the file
00971 //
00972    if ((rc = fp->open(fn, (XrdSfsFileOpenMode)openopts,
00973                      (mode_t)mode, CRED, opaque)))
00974       {rc = fsError(rc, fp->error); delete fp; return rc;}
00975 
00976 // Obtain a hyper file object
00977 //
00978    if (!(xp=new XrdXrootdFile(Link->ID,fp,usage,isAsync,Link->sfOK,&statbuf)))
00979       {delete fp;
00980        snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
00981        eDest.Emsg("Xeq", ebuff);
00982        return Response.Send(kXR_NoMemory, ebuff);
00983       }
00984 
00985 // Serialize the link
00986 //
00987    Link->Serialize();
00988    *ebuff = '\0';
00989 
00990 // Lock this file
00991 //
00992    if (!(popt & XROOTDXP_NOLK) && (rc = Locker->Lock(xp, doforce)))
00993       {const char *who;
00994        if (rc > 0) who = (rc > 1 ? "readers" : "reader");
00995           else {   rc = -rc;
00996                    who = (rc > 1 ? "writers" : "writer");
00997                }
00998        snprintf(ebuff, sizeof(ebuff)-1,
00999                 "%s file %s is already opened by %d %s; open denied.",
01000                 ('r' == usage ? "Input" : "Output"), fn, rc, who);
01001        delete fp; xp->XrdSfsp = 0; delete xp;
01002        eDest.Emsg("Xeq", ebuff);
01003        return Response.Send(kXR_FileLocked, ebuff);
01004       }
01005 
01006 // Create a file table for this link if it does not have one
01007 //
01008    if (!FTab) FTab = new XrdXrootdFileTable();
01009 
01010 // Insert this file into the link's file table
01011 //
01012    if (!FTab || (fhandle = FTab->Add(xp)) < 0)
01013       {delete xp;
01014        snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
01015        eDest.Emsg("Xeq", ebuff);
01016        return Response.Send(kXR_NoMemory, ebuff);
01017       }
01018 
01019 // Document forced opens
01020 //
01021    if (doforce)
01022       {int rdrs, wrtrs;
01023        Locker->numLocks(xp, rdrs, wrtrs);
01024        if (('r' == usage && wrtrs) || ('w' == usage && rdrs) || wrtrs > 1)
01025           {snprintf(ebuff, sizeof(ebuff)-1,
01026              "%s file %s forced opened with %d reader(s) and %d writer(s).",
01027              ('r' == usage ? "Input" : "Output"), fn, rdrs, wrtrs);
01028            eDest.Emsg("Xeq", ebuff);
01029           }
01030       }
01031 
01032 // Determine if file is compressed
01033 //
01034    if (!compchk) 
01035       {resplen = sizeof(myResp.fhandle);
01036        memset(&myResp, 0, sizeof(myResp));
01037       }
01038       else {int cpsize;
01039             fp->getCXinfo((char *)myResp.cptype, cpsize);
01040             if (cpsize) {myResp.cpsize = static_cast<kXR_int32>(htonl(cpsize));
01041                          resplen = sizeof(myResp);
01042                         } else myResp.cpsize = 0;
01043            }
01044 
01045 // If client wants a stat in open, return the stat information
01046 //
01047    if (retStat)
01048       {retStat = StatGen(statbuf, ebuff);
01049        IOResp[1].iov_base = (char *)&myResp; IOResp[1].iov_len = sizeof(myResp);
01050        IOResp[2].iov_base =         ebuff;   IOResp[2].iov_len = retStat;
01051        resplen = sizeof(myResp) + retStat;
01052       }
01053 
01054 // If we are monitoring, send off a path to dictionary mapping
01055 //
01056    if (monFILE && Monitor) 
01057       {xp->FileID = Monitor->Map(XROOTD_MON_MAPPATH, Link->ID, fn);
01058        Monitor->Open(xp->FileID, statbuf.st_size);
01059       }
01060 
01061 // Insert the file handle
01062 //
01063    memcpy((void *)myResp.fhandle,(const void *)&fhandle,sizeof(myResp.fhandle));
01064    numFiles++;
01065 
01066 // Respond
01067 //
01068    if (retStat)  return Response.Send(IOResp, 3, resplen);
01069       else       return Response.Send((void *)&myResp, resplen);
01070 }
01071 
01072 /******************************************************************************/
01073 /*                               d o _ P i n g                                */
01074 /******************************************************************************/
01075   
01076 int XrdXrootdProtocol::do_Ping()
01077 {
01078 
01079 // Keep Statistics
01080 //
01081    UPSTATS(miscCnt);
01082 
01083 // This is a basic nop
01084 //
01085    return Response.Send();
01086 }
01087 
01088 /******************************************************************************/
01089 /*                            d o _ P r e p a r e                             */
01090 /******************************************************************************/
01091   
01092 int XrdXrootdProtocol::do_Prepare()
01093 {
01094    int rc, hport, pathnum = 0;
01095    const char *opaque;
01096    char opts, hname[32], reqid[64], nidbuff[512], *path;
01097    XrdOucErrInfo myError(Link->ID);
01098    XrdOucTokenizer pathlist(argp->buff);
01099    XrdOucTList *pFirst=0, *pP, *pLast = 0;
01100    XrdOucTList *oFirst=0, *oP, *oLast = 0;
01101    XrdOucTListHelper pHelp(&pFirst), oHelp(&oFirst);
01102    XrdXrootdPrepArgs pargs(0, 0);
01103    XrdSfsPrep fsprep;
01104 
01105 // Grab the options
01106 //
01107    opts = Request.prepare.options;
01108 
01109 // Check for static routing
01110 //
01111    if (Route[RD_prepstg].Port && ((opts & kXR_stage) || (opts & kXR_cancel)))
01112       return Response.Send(kXR_redirect,Route[RD_prepstg].Port,Route[RD_prepstg].Host);
01113    if (Route[RD_prepare].Port)
01114       return Response.Send(kXR_redirect,Route[RD_prepare].Port,Route[RD_prepare].Host);
01115 
01116 // Get a request ID for this prepare and check for static routine
01117 //
01118    if (opts & kXR_stage && !(opts & kXR_cancel)) 
01119       {XrdOucReqID::ID(reqid, sizeof(reqid)); 
01120        fsprep.opts = Prep_STAGE | (opts & kXR_coloc ? Prep_COLOC : 0);
01121       }
01122       else {reqid[0] = '*'; reqid[1] = '\0';  fsprep.opts = 0;}
01123 
01124 // Initialize the fsile system prepare arg list
01125 //
01126    fsprep.reqid   = reqid;
01127    fsprep.paths   = 0;
01128    fsprep.oinfo   = 0;
01129    fsprep.opts   |= Prep_PRTY0 | (opts & kXR_fresh ? Prep_FRESH : 0);
01130    fsprep.notify  = 0;
01131 
01132 // Check if this is a cancel request
01133 //
01134    if (opts & kXR_cancel)
01135       {if (!(path = pathlist.GetLine()))
01136           return Response.Send(kXR_ArgMissing, "Prepare requestid not specified");
01137        if (!XrdOucReqID::isMine(path, hport, hname, sizeof(hname)))
01138           {if (!hport) return Response.Send(kXR_ArgInvalid,
01139                              "Prepare requestid owned by an unknown server");
01140            TRACEI(REDIR, Response.ID() <<"redirecting to " << hname <<':' <<hport);
01141            return Response.Send(kXR_redirect, hport, hname);
01142           }
01143        fsprep.reqid = path;
01144        if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
01145           return fsError(rc, myError);
01146        rc = Response.Send();
01147        XrdXrootdPrepare::Logdel(path);
01148        return rc;
01149       }
01150 
01151 // Cycle through all of the paths in the list
01152 //
01153    while((path = pathlist.GetLine()))
01154         {if (rpCheck(path, &opaque)) return rpEmsg("Preparing", path);
01155          if (!Squash(path))          return vpEmsg("Preparing", path);
01156          pP = new XrdOucTList(path, pathnum);
01157          (pLast ? (pLast->next = pP) : (pFirst = pP)); pLast = pP;
01158          oP = new XrdOucTList(opaque, 0);
01159          (oLast ? (oLast->next = oP) : (oFirst = oP)); oLast = oP;
01160          pathnum++;
01161         }
01162 
01163 // Make sure we have at least one path
01164 //
01165    if (!pFirst)
01166       return Response.Send(kXR_ArgMissing, "No prepare paths specified");
01167 
01168 // Issue the prepare
01169 //
01170    if (opts & kXR_notify)
01171       {fsprep.notify  = nidbuff;
01172        sprintf(nidbuff, Notify, Link->FDnum(), Link->ID);
01173        fsprep.opts = (opts & kXR_noerrs ? Prep_SENDAOK : Prep_SENDACK);
01174       }
01175    if (opts & kXR_wmode) fsprep.opts |= Prep_WMODE;
01176    fsprep.paths = pFirst;
01177    fsprep.oinfo = oFirst;
01178    if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
01179       return fsError(rc, myError);
01180 
01181 // Perform final processing
01182 //
01183    if (!(opts & kXR_stage)) rc = Response.Send();
01184       else {rc = Response.Send(reqid, strlen(reqid));
01185             pargs.reqid=reqid;
01186             pargs.user=Link->ID;
01187             pargs.paths=pFirst;
01188             XrdXrootdPrepare::Log(pargs);
01189             pargs.reqid = 0;
01190            }
01191    return rc;
01192 }
01193   
01194 /******************************************************************************/
01195 /*                           d o _ P r o t o c o l                            */
01196 /******************************************************************************/
01197   
01198 int XrdXrootdProtocol::do_Protocol()
01199 {
01200     static ServerResponseBody_Protocol Resp
01201                  = {static_cast<kXR_int32>(htonl(XROOTD_VERSBIN)),
01202                     static_cast<kXR_int32>(htonl(kXR_DataServer))};
01203 
01204 // Keep Statistics
01205 //
01206    UPSTATS(miscCnt);
01207 
01208 // Return info
01209 //
01210     if (isRedir) Resp.flags = static_cast<kXR_int32>(htonl(kXR_LBalServer));
01211     return Response.Send((void *)&Resp, sizeof(Resp));
01212 }
01213 
01214 /******************************************************************************/
01215 /*                            d o _ P u t f i l e                             */
01216 /******************************************************************************/
01217   
01218 int XrdXrootdProtocol::do_Putfile()
01219 {
01220    int popts, buffsz;
01221 
01222 // Keep Statistics
01223 //
01224    UPSTATS(putfCnt);
01225 
01226 // Unmarshall the data
01227 //
01228    popts  = int(ntohl(Request.putfile.options));
01229    buffsz = int(ntohl(Request.putfile.buffsz));
01230 
01231    return Response.Send(kXR_Unsupported, "putfile request is not supported");
01232 }
01233 
01234 /******************************************************************************/
01235 /*                              d o _ Q c o n f                               */
01236 /******************************************************************************/
01237   
01238 int XrdXrootdProtocol::do_Qconf()
01239 {
01240    XrdOucTokenizer qcargs(argp->buff);
01241    char *val, buff[1024], *bp=buff;
01242    int n, bleft = sizeof(buff);
01243 
01244 // Get the first argument
01245 //
01246    if (!qcargs.GetLine() || !(val = qcargs.GetToken()))
01247       return Response.Send(kXR_ArgMissing, "query config argument not specified.");
01248 
01249 // Trace this query variable
01250 //
01251    do {TRACEP(DEBUG, "query config " <<val);
01252        if (bleft < 32) break;
01253 
01254    // Now determine what the user wants to query
01255    //
01256         if (!strcmp("bind_max", val))
01257            {n = sprintf(bp, "%d\n", maxStreams-1);
01258             bp += n; bleft -= n;
01259            }
01260    else if (!strcmp("pio_max", val))
01261            {n = sprintf(bp, "%d\n", maxPio+1);
01262             bp += n; bleft -= n;
01263            }
01264    else if (!strcmp("readv_ior_max", val))
01265            {n = sprintf(bp, "%d\n", maxTransz - (int)sizeof(readahead_list));
01266             bp += n; bleft -= n;
01267            }
01268    else if (!strcmp("readv_iov_max", val)) 
01269            {n = sprintf(bp, "%d\n", maxRvecsz);
01270             bp += n; bleft -= n;
01271            }
01272    else if (!strcmp("wan_port", val) && WANPort)
01273            {n = sprintf(bp, "%d\n", WANPort);
01274             bp += n; bleft -= n;
01275            }
01276    else if (!strcmp("wan_window", val) && WANPort)
01277            {n = sprintf(bp, "%d\n", WANWindow);
01278             bp += n; bleft -= n;
01279            }
01280    else if (!strcmp("window", val) && Window)
01281            {n = sprintf(bp, "%d\n", Window);
01282             bp += n; bleft -= n;
01283            }
01284    else {n = strlen(val);
01285          if (bleft <= n) break;
01286          strcpy(bp, val); bp +=n; *bp = '\n'; bp++;
01287          bleft -= (n+1);
01288         }
01289    } while((val = qcargs.GetToken()));
01290 
01291 // Make sure all ended well
01292 //
01293    if (val) 
01294       return Response.Send(kXR_ArgTooLong, "too many query config arguments.");
01295 
01296 // All done
01297 //
01298    return Response.Send(buff, sizeof(buff) - bleft);
01299 }
01300   
01301 /******************************************************************************/
01302 /*                                d o _ Q f h                                 */
01303 /******************************************************************************/
01304 
01305 int XrdXrootdProtocol::do_Qfh()
01306 {
01307    static const int fsctl_cmd1 = SFS_FCTL_STATV;
01308    static XrdXrootdCallBack qryCB("query");
01309    XrdOucErrInfo myError(Link->ID, &qryCB, ReqID.getID());
01310    XrdXrootdFHandle fh(Request.query.fhandle);
01311    XrdXrootdFile *fp;
01312    short qopt = (short)ntohs(Request.query.infotype);
01313    int rc, fsctl_cmd;
01314 
01315 // Update misc stats count
01316 //
01317    UPSTATS(miscCnt);
01318 
01319 // Perform the appropriate query
01320 //
01321    switch(qopt)
01322          {case kXR_Qvisa:   fsctl_cmd = fsctl_cmd1;
01323                             break;
01324           default:          return Response.Send(kXR_ArgMissing, 
01325                                    "Required query argument not present");
01326          }
01327 
01328 // Find the file object
01329 //
01330    if (!FTab || !(fp = FTab->Get(fh.handle)))
01331       return Response.Send(kXR_FileNotOpen,
01332                            "query does not refer to an open file");
01333 
01334 // Preform the actual function
01335 //
01336    rc = fp->XrdSfsp->fctl(fsctl_cmd, 0, myError);
01337    TRACEP(FS, "query rc=" <<rc <<" fh=" <<fh.handle);
01338 
01339 // Return appropriately
01340 //
01341    if (SFS_OK != rc) return fsError(rc, myError);
01342    return Response.Send();
01343 }
01344   
01345 /******************************************************************************/
01346 /*                            d o _ Q o p a q u e                             */
01347 /******************************************************************************/
01348   
01349 int XrdXrootdProtocol::do_Qopaque(short qopt)
01350 {
01351    XrdOucErrInfo myError(Link->ID);
01352    XrdSfsFSctl myData;
01353    const char *opaque, *Act, *AData;
01354    int fsctl_cmd, rc, dlen = Request.query.dlen;
01355 
01356 // Process unstructured as well as structured (path/opaque) requests
01357 //
01358    if (qopt == kXR_Qopaque)
01359       {myData.Arg1 = argp->buff; myData.Arg1Len = dlen;
01360        myData.Arg2 = 0;          myData.Arg1Len = 0;
01361        fsctl_cmd = SFS_FSCTL_PLUGIO;
01362        Act = " qopaque '"; AData = "...";
01363       } else {
01364        // Check for static routing (this falls under stat)
01365        //
01366        if (Route[RD_stat].Port)
01367           return Response.Send(kXR_redirect,Route[RD_stat].Port,Route[RD_stat].Host);
01368 
01369        // Prescreen the path
01370        //
01371        if (rpCheck(argp->buff, &opaque)) return rpEmsg("Querying", argp->buff);
01372        if (!Squash(argp->buff))          return vpEmsg("Querying", argp->buff);
01373 
01374        // Setup arguments
01375        //
01376        myData.Arg1    = argp->buff;
01377        myData.Arg1Len = (opaque ? opaque - argp->buff - 1    : dlen);
01378        myData.Arg2    = opaque;
01379        myData.Arg2Len = (opaque ? argp->buff + dlen - opaque : 0);
01380        fsctl_cmd = SFS_FSCTL_PLUGIN;
01381        Act = " qopaquf '"; AData = argp->buff;
01382       }
01383 
01384 // Preform the actual function using the supplied arguments
01385 //
01386    rc = osFS->FSctl(fsctl_cmd, myData, myError, CRED);
01387    TRACEP(FS, "rc=" <<rc <<Act <<AData <<"'");
01388    if (rc == SFS_OK) Response.Send("");
01389    return fsError(rc, myError);
01390 }
01391 
01392 /******************************************************************************/
01393 /*                             d o _ Q s p a c e                              */
01394 /******************************************************************************/
01395   
01396 int XrdXrootdProtocol::do_Qspace()
01397 {
01398    static const int fsctl_cmd = SFS_FSCTL_STATLS;
01399    XrdOucErrInfo myError(Link->ID);
01400    const char *opaque;
01401    int n, rc;
01402 
01403 // Check for static routing
01404 //
01405    if (Route[RD_stat].Port) 
01406       return Response.Send(kXR_redirect,Route[RD_stat].Port,Route[RD_stat].Host);
01407 
01408 // Prescreen the path
01409 //
01410    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
01411    if (!Squash(argp->buff))          return vpEmsg("Stating", argp->buff);
01412 
01413 // Add back the opaque info
01414 //
01415    if (opaque)
01416       {n = strlen(argp->buff); argp->buff[n] = '?';
01417        if ((argp->buff)+n != opaque-1) strcpy(&argp->buff[n+1], opaque);
01418       }
01419 
01420 // Preform the actual function using the supplied logical FS name
01421 //
01422    rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
01423    TRACEP(FS, "rc=" <<rc <<" qspace '" <<argp->buff <<"'");
01424    if (rc == SFS_OK) Response.Send("");
01425    return fsError(rc, myError);
01426 }
01427 
01428 /******************************************************************************/
01429 /*                              d o _ Q u e r y                               */
01430 /******************************************************************************/
01431   
01432 int XrdXrootdProtocol::do_Query()
01433 {
01434     short qopt = (short)ntohs(Request.query.infotype);
01435 
01436 // Perform the appropriate query
01437 //
01438    switch(qopt)
01439          {case kXR_QStats: return SI->Stats(Response,
01440                               (Request.header.dlen ? argp->buff : "a"));
01441           case kXR_Qcksum:  return do_CKsum(0);
01442           case kXR_Qckscan: return do_CKsum(1);
01443           case kXR_Qconfig: return do_Qconf();
01444           case kXR_Qspace:  return do_Qspace();
01445           case kXR_Qxattr:  return do_Qxattr();
01446           case kXR_Qopaque:
01447           case kXR_Qopaquf: return do_Qopaque(qopt);
01448           default:          break;
01449          }
01450 
01451 // Whatever we have, it's not valid
01452 //
01453    return Response.Send(kXR_ArgInvalid, 
01454                         "Invalid information query type code");
01455 }
01456 
01457 /******************************************************************************/
01458 /*                             d o _ Q x a t t r                              */
01459 /******************************************************************************/
01460   
01461 int XrdXrootdProtocol::do_Qxattr()
01462 {
01463    static XrdXrootdCallBack statCB("stat");
01464    static const int fsctl_cmd = SFS_FSCTL_STATXA;
01465    int rc;
01466    const char *opaque;
01467    XrdOucErrInfo myError(Link->ID, &statCB, ReqID.getID());
01468 
01469 // Check for static routing
01470 //
01471    if (Route[RD_stat].Port) 
01472       return Response.Send(kXR_redirect,Route[RD_stat].Port,Route[RD_stat].Host);
01473 
01474 // Prescreen the path
01475 //
01476    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
01477    if (!Squash(argp->buff))          return vpEmsg("Stating", argp->buff);
01478 
01479 // Preform the actual function
01480 //
01481    rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
01482    TRACEP(FS, "rc=" <<rc <<" qxattr " <<argp->buff);
01483    return fsError(rc, myError);
01484 }
01485   
01486 /******************************************************************************/
01487 /*                               d o _ R e a d                                */
01488 /******************************************************************************/
01489   
01490 int XrdXrootdProtocol::do_Read()
01491 {
01492    int pathID, retc;
01493    XrdXrootdFHandle fh(Request.read.fhandle);
01494    numReads++;
01495 
01496 // We first handle the pre-read list, if any. We do it this way because of
01497 // a historical glitch in the protocol. One should really not piggy back a
01498 // pre-read on top of a read, though it is allowed.
01499 //
01500    if (!Request.header.dlen) pathID = 0;
01501       else if (do_ReadNone(retc, pathID)) return retc;
01502 
01503 // Unmarshall the data
01504 //
01505    myIOLen  = ntohl(Request.read.rlen);
01506               n2hll(Request.read.offset, myOffset);
01507 
01508 // Find the file object
01509 //
01510    if (!FTab || !(myFile = FTab->Get(fh.handle)))
01511       return Response.Send(kXR_FileNotOpen,
01512                            "read does not refer to an open file");
01513 
01514 // Short circuit processing is read length is zero
01515 //
01516    TRACEP(FS, pathID <<" fh=" <<fh.handle <<" read " <<myIOLen <<'@' <<myOffset);
01517    if (!myIOLen) return Response.Send();
01518 
01519 // If we are monitoring, insert a read entry
01520 //
01521    if (monIO && Monitor) Monitor->Add_rd(myFile->FileID, Request.read.rlen,
01522                                          Request.read.offset);
01523 
01524 // See if an alternate path is required, offload the read
01525 //
01526    if (pathID) return do_Offload(pathID, 0);
01527 
01528 // Now read all of the data (do pre-reads first)
01529 //
01530    return do_ReadAll();
01531 }
01532 
01533 /******************************************************************************/
01534 /*                            d o _ R e a d A l l                             */
01535 /******************************************************************************/
01536 
01537 // myFile   = file to be read
01538 // myOffset = Offset at which to read
01539 // myIOLen  = Number of bytes to read from file and write to socket
01540   
01541 int XrdXrootdProtocol::do_ReadAll(int asyncOK)
01542 {
01543    int rc, xframt, Quantum = (myIOLen > maxBuffsz ? maxBuffsz : myIOLen);
01544    char *buff;
01545 
01546 // If this file is memory mapped, short ciruit all the logic and immediately
01547 // transfer the requested data to minimize latency.
01548 //
01549    if (myFile->isMMapped)
01550       {     if (myOffset >= myFile->fSize) return Response.Send();
01551        else if (myOffset+myIOLen <= myFile->fSize)
01552                return Response.Send(myFile->mmAddr+myOffset, myIOLen);
01553        else    return Response.Send(myFile->mmAddr+myOffset,
01554                                     myFile->fSize -myOffset);
01555       }
01556 
01557 // If we are sendfile enabled, then just send the file if possible
01558 //
01559    if (myFile->sfEnabled && myIOLen >= as_minsfsz
01560    &&  myOffset+myIOLen <= myFile->fSize)
01561       return Response.Send(myFile->fdNum, myOffset, myIOLen);
01562 
01563 // If we are in async mode, schedule the read to ocur asynchronously
01564 //
01565    if (asyncOK && myFile->AsyncMode)
01566       {if (myIOLen >= as_miniosz && Link->UseCnt() < as_maxperlnk)
01567           if ((rc = aio_Read()) != -EAGAIN) return rc;
01568        SI->AsyncRej++;
01569       }
01570 
01571 // Make sure we have a large enough buffer
01572 //
01573    if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
01574       {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
01575       else if (hcNow < hcNext) hcNow++;
01576    buff = argp->buff;
01577 
01578 // Now read all of the data
01579 //
01580    do {if ((xframt = myFile->XrdSfsp->read(myOffset, buff, Quantum)) <= 0) break;
01581        myFile->readCnt += xframt;
01582        if (xframt >= myIOLen) return Response.Send(buff, xframt);
01583        if (Response.Send(kXR_oksofar, buff, xframt) < 0) return -1;
01584        myOffset += xframt; myIOLen -= xframt;
01585        if (myIOLen < Quantum) Quantum = myIOLen;
01586       } while(myIOLen);
01587 
01588 // Determine why we ended here
01589 //
01590    if (xframt == 0) return Response.Send();
01591    return Response.Send(kXR_FSError, myFile->XrdSfsp->error.getErrText());
01592 }
01593 
01594 /******************************************************************************/
01595 /*                           d o _ R e a d N o n e                            */
01596 /******************************************************************************/
01597   
01598 int XrdXrootdProtocol::do_ReadNone(int &retc, int &pathID)
01599 {
01600    XrdXrootdFHandle fh;
01601    int ralsz = Request.header.dlen;
01602    struct read_args *rargs=(struct read_args *)(argp->buff);
01603    struct readahead_list *ralsp = (readahead_list *)(rargs+sizeof(read_args));
01604 
01605 // Return the pathid
01606 //
01607    pathID = static_cast<int>(rargs->pathid);
01608    if ((ralsz -= sizeof(read_args)) <= 0) return 0;
01609 
01610 // Make sure that we have a proper pre-read list
01611 //
01612    if (ralsz%sizeof(readahead_list))
01613       {Response.Send(kXR_ArgInvalid, "Invalid length for read ahead list");
01614        return 1;
01615       }
01616 
01617 // Run down the pre-read list
01618 //
01619    while(ralsz > 0)
01620         {myIOLen  = ntohl(ralsp->rlen);
01621                     n2hll(ralsp->offset, myOffset);
01622          memcpy((void *)&fh.handle, (const void *)ralsp->fhandle,
01623                   sizeof(fh.handle));
01624          TRACEP(FS, "fh=" <<fh.handle <<" read " <<myIOLen <<'@' <<myOffset);
01625          if (!FTab || !(myFile = FTab->Get(fh.handle)))
01626             {retc = Response.Send(kXR_FileNotOpen,
01627                              "preread does not refer to an open file");
01628              return 1;
01629             }
01630          myFile->XrdSfsp->read(myOffset, myIOLen);
01631          ralsz -= sizeof(struct readahead_list);
01632          ralsp++;
01633          numReads++;
01634         };
01635 
01636 // All done
01637 //
01638    return 0;
01639 }
01640 
01641 /******************************************************************************/
01642 /*                               d o _ R e a d V                              */
01643 /******************************************************************************/
01644   
01645 int XrdXrootdProtocol::do_ReadV()
01646 {
01647 // This will read multiple buffers at the same time in an attempt to avoid
01648 // the latency in a network. The information with the offsets and lengths
01649 // of the information to read is passed as a data buffer... then we decode
01650 // it and put all the individual buffers in a single one (it's up to the)
01651 // client to interpret it. Code originally developed by Leandro Franco, CERN.
01652 //
01653    const int hdrSZ     = sizeof(readahead_list);
01654    XrdXrootdFHandle currFH, lastFH((kXR_char *)"\xff\xff\xff\xff");
01655    struct readahead_list rdVec[maxRvecsz];
01656    long long totLen;
01657    int rdVecNum, rdVecLen = Request.header.dlen;
01658    int i, rc, xframt, Quantum, Qleft;
01659    char *buffp;
01660 
01661 // Compute number of elements in the read vector and make sure we have no
01662 // partial elements.
01663 //
01664    rdVecNum = rdVecLen / sizeof(readahead_list);
01665    if ( (rdVecLen <= 0) || (rdVecNum*hdrSZ != rdVecLen) )
01666       {Response.Send(kXR_ArgInvalid, "Read vector is invalid");
01667        return 0;
01668       }
01669 
01670 // Make sure that we can copy the read vector to our local stack. We must impose 
01671 // a limit on it's size. We do this to be able to reuse the data buffer to 
01672 // prevent cross-cpu memory cache synchronization.
01673 //
01674    if (rdVecLen > static_cast<int>(sizeof(rdVec)))
01675       {Response.Send(kXR_ArgTooLong, "Read vector is too long");
01676        return 0;
01677       }
01678    memcpy(rdVec, argp->buff, rdVecLen);
01679 
01680 // Run down the list and compute the total size of the read. No individual
01681 // read may be greater than the maximum transfer size.
01682 //
01683    totLen = rdVecLen; xframt = maxTransz - hdrSZ;
01684    for (i = 0; i < rdVecNum; i++) 
01685        {totLen += (rdVec[i].rlen = ntohl(rdVec[i].rlen));
01686         if (rdVec[i].rlen > xframt)
01687            {Response.Send(kXR_NoMemory, "Single readv transfer is too large");
01688             return 0;
01689            }
01690        }
01691 
01692 // We limit the total size of the read to be 2GB for convenience
01693 //
01694    if (totLen > 0x7fffffffLL)
01695       {Response.Send(kXR_NoMemory, "Total readv transfer is too large");
01696        return 0;
01697       }
01698    if ((Quantum = static_cast<int>(totLen)) > maxTransz) Quantum = maxTransz;
01699    
01700 // Now obtain the right size buffer
01701 //
01702    if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
01703       {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
01704       else if (hcNow < hcNext) hcNow++;
01705 
01706 // Check that we really have at least one file open. This needs to be done 
01707 // only once as this code runs in the control thread.
01708 //
01709    if (!FTab) return Response.Send(kXR_FileNotOpen,
01710                               "readv does not refer to an open file");
01711 
01712 // Run down the pre-read list. Each read element is prefixed by the verctor
01713 // element. We also break the reads into Quantum sized units. We do the
01714 //
01715    Qleft = Quantum; buffp = argp->buff;
01716    for (i = 0; i < rdVecNum; i++)
01717        {
01718         // Every request could come from a different file
01719         //
01720         currFH.Set(rdVec[i].fhandle);
01721         if (currFH.handle != lastFH.handle)
01722            {if (!(myFile = FTab->Get(currFH.handle)))
01723                return Response.Send(kXR_FileNotOpen,
01724                                "readv does not refer to an open file");
01725                else lastFH.handle = currFH.handle;
01726            }
01727       
01728         // Read in the vector, segmenting as needed. Note that we gaurantee
01729         // that a single readv element will never need to be segmented.
01730         //
01731         myIOLen  = rdVec[i].rlen;
01732         n2hll(rdVec[i].offset, myOffset);
01733         if (Qleft < (myIOLen + hdrSZ))
01734            {if (Response.Send(kXR_oksofar,argp->buff,Quantum-Qleft) < 0)
01735                return -1;
01736             Qleft = Quantum;
01737             buffp = argp->buff;
01738            }
01739         TRACEP(FS,"fh=" <<currFH.handle <<" readV " << myIOLen <<'@' <<myOffset);
01740         if ((xframt = myFile->XrdSfsp->read(myOffset,buffp+hdrSZ,myIOLen)) < 0)
01741            break;
01742         myFile->readCnt += xframt; numReads++;
01743         rdVec[i].rlen = htonl(xframt);
01744         memcpy(buffp, &rdVec[i], hdrSZ);
01745         buffp += (xframt+hdrSZ); Qleft -= (xframt+hdrSZ);
01746        }
01747    
01748 // Determine why we ended here
01749 //
01750    if (i >= rdVecNum)
01751       return Response.Send(argp->buff, Quantum-Qleft);
01752    return Response.Send(kXR_FSError, myFile->XrdSfsp->error.getErrText());
01753 }
01754   
01755 /******************************************************************************/
01756 /*                                 d o _ R m                                  */
01757 /******************************************************************************/
01758   
01759 int XrdXrootdProtocol::do_Rm()
01760 {
01761    int rc;
01762    const char *opaque;
01763    XrdOucErrInfo myError(Link->ID);
01764 
01765 // Check for static routing
01766 //
01767    if (Route[RD_rm].Port) 
01768       return Response.Send(kXR_redirect,Route[RD_rm].Port,Route[RD_rm].Host);
01769 
01770 // Prescreen the path
01771 //
01772    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
01773    if (!Squash(argp->buff))          return vpEmsg("Removing", argp->buff);
01774 
01775 // Preform the actual function
01776 //
01777    rc = osFS->rem(argp->buff, myError, CRED, opaque);
01778    TRACEP(FS, "rc=" <<rc <<" rm " <<argp->buff);
01779    if (SFS_OK == rc) return Response.Send();
01780 
01781 // An error occured
01782 //
01783    return fsError(rc, myError);
01784 }
01785 
01786 /******************************************************************************/
01787 /*                              d o _ R m d i r                               */
01788 /******************************************************************************/
01789   
01790 int XrdXrootdProtocol::do_Rmdir()
01791 {
01792    int rc;
01793    const char *opaque;
01794    XrdOucErrInfo myError(Link->ID);
01795 
01796 // Check for static routing
01797 //
01798    if (Route[RD_rmdir].Port) 
01799       return Response.Send(kXR_redirect,Route[RD_rmdir].Port,Route[RD_rmdir].Host);
01800 
01801 // Prescreen the path
01802 //
01803    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
01804    if (!Squash(argp->buff))          return vpEmsg("Removing", argp->buff);
01805 
01806 // Preform the actual function
01807 //
01808    rc = osFS->remdir(argp->buff, myError, CRED, opaque);
01809    TRACEP(FS, "rc=" <<rc <<" rmdir " <<argp->buff);
01810    if (SFS_OK == rc) return Response.Send();
01811 
01812 // An error occured
01813 //
01814    return fsError(rc, myError);
01815 }
01816 
01817 /******************************************************************************/
01818 /*                                d o _ S e t                                 */
01819 /******************************************************************************/
01820   
01821 int XrdXrootdProtocol::do_Set()
01822 {
01823    XrdOucTokenizer setargs(argp->buff);
01824    char *val, *rest;
01825 
01826 // Get the first argument
01827 //
01828    if (!setargs.GetLine() || !(val = setargs.GetToken(&rest)))
01829       return Response.Send(kXR_ArgMissing, "set argument not specified.");
01830 
01831 // Trace this set
01832 //
01833    TRACEP(DEBUG, "set " <<val <<' ' <<rest);
01834 
01835 // Now determine what the user wants to set
01836 //
01837         if (!strcmp("appid", val))
01838            {while(*rest && *rest == ' ') rest++;
01839             eDest.Emsg("Xeq", Link->ID, "appid", rest);
01840             return Response.Send();
01841            }
01842    else if (!strcmp("monitor", val)) return do_Set_Mon(setargs);
01843 
01844 // All done
01845 //
01846    return Response.Send(kXR_ArgInvalid, "invalid set parameter");
01847 }
01848 
01849 /******************************************************************************/
01850 /*                            d o _ S e t _ M o n                             */
01851 /******************************************************************************/
01852 
01853 // Process: set monitor {off | on} [appid] | info [info]}
01854 
01855 int XrdXrootdProtocol::do_Set_Mon(XrdOucTokenizer &setargs)
01856 {
01857   char *val, *appid;
01858   kXR_unt32 myseq = 0;
01859 
01860 // Get the first argument
01861 //
01862    if (!(val = setargs.GetToken(&appid)))
01863       return Response.Send(kXR_ArgMissing,"set monitor argument not specified.");
01864 
01865 // For info requests, nothing changes. However, info events must have been
01866 // enabled for us to record them. Route the information via the static
01867 // monitor entry, since it knows how to forward the information.
01868 //
01869    if (!strcmp(val, "info"))
01870       {if (appid && XrdXrootdMonitor::monINFO)
01871           {while(*appid && *appid == ' ') appid++;
01872            if (strlen(appid) > 1024) appid[1024] = '\0';
01873            if (*appid) myseq = XrdXrootdMonitor::Map(XROOTD_MON_MAPINFO,
01874                                Link->ID, appid);
01875           }
01876        return Response.Send((void *)&myseq, sizeof(myseq));
01877       }
01878 
01879 // Determine if on do appropriate processing
01880 //
01881    if (!strcmp(val, "on"))
01882       {if (Monitor || (Monitor = XrdXrootdMonitor::Alloc(1)))
01883           {if (appid && XrdXrootdMonitor::monIO)
01884               {while(*appid && *appid == ' ') appid++;
01885                if (*appid) Monitor->appID(appid);
01886               }
01887            monIO   =  XrdXrootdMonitor::monIO;
01888            monFILE =  XrdXrootdMonitor::monFILE;
01889            if (XrdXrootdMonitor::monUSER && !monUID)
01890               monUID = XrdXrootdMonitor::Map(XROOTD_MON_MAPUSER, Link->ID, 0);
01891           }
01892        return Response.Send();
01893       }
01894 
01895 // Determine if off and do appropriate processing
01896 //
01897    if (!strcmp(val, "off"))
01898       {if (Monitor)
01899           {if (appid && XrdXrootdMonitor::monIO)
01900               {while(*appid && *appid == ' ') appid++;
01901                if (*appid) Monitor->appID(appid);
01902               }
01903            Monitor->unAlloc(Monitor); Monitor = 0; monIO = monFILE = 0;
01904           }
01905        return Response.Send();
01906       }
01907 
01908 // Improper request
01909 //
01910    return Response.Send(kXR_ArgInvalid, "invalid set monitor argument");
01911 }
01912   
01913 /******************************************************************************/
01914 /*                               d o _ S t a t                                */
01915 /******************************************************************************/
01916   
01917 int XrdXrootdProtocol::do_Stat()
01918 {
01919    static XrdXrootdCallBack statCB("stat");
01920    static const int fsctl_cmd = SFS_FSCTL_STATFS;
01921    int rc;
01922    const char *opaque;
01923    char xxBuff[256];
01924    struct stat buf;
01925    XrdOucErrInfo myError(Link->ID, &statCB, ReqID.getID());
01926 
01927 // Check for static routing
01928 //
01929    if (Route[RD_stat].Port) 
01930       return Response.Send(kXR_redirect,Route[RD_stat].Port,Route[RD_stat].Host);
01931 
01932 // Prescreen the path
01933 //
01934    if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
01935    if (!Squash(argp->buff))          return vpEmsg("Stating", argp->buff);
01936 
01937 // Preform the actual function
01938 //
01939    if (Request.stat.options & kXR_vfs)
01940       {rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
01941        TRACEP(FS, "rc=" <<rc <<" statfs " <<argp->buff);
01942        if (rc == SFS_OK) Response.Send("");
01943       } else {
01944        rc = osFS->stat(argp->buff, &buf, myError, CRED, opaque);
01945        TRACEP(FS, "rc=" <<rc <<" stat " <<argp->buff);
01946        if (rc == SFS_OK) return Response.Send(xxBuff, StatGen(buf, xxBuff));
01947       }
01948    return fsError(rc, myError);
01949 }
01950 
01951 /******************************************************************************/
01952 /*                              d o _ S t a t x                               */
01953 /******************************************************************************/
01954   
01955 int XrdXrootdProtocol::do_Statx()
01956 {
01957    static XrdXrootdCallBack statxCB("xstat");
01958    int rc;
01959    const char *opaque;
01960    char *path, *respinfo = argp->buff;
01961    mode_t mode;
01962    XrdOucErrInfo myError(Link->ID, &statxCB, ReqID.getID());
01963    XrdOucTokenizer pathlist(argp->buff);
01964 
01965 // Cycle through all of the paths in the list
01966 //
01967    while((path = pathlist.GetLine()))
01968         {if (rpCheck(path, &opaque)) return rpEmsg("Stating", path);
01969          if (!Squash(path))          return vpEmsg("Stating", path);
01970          rc = osFS->stat(path, mode, myError, CRED, opaque);
01971          TRACEP(FS, "rc=" <<rc <<" stat " <<path);
01972          if (rc != SFS_OK)                    return fsError(rc, myError);
01973             else {if (mode == (mode_t)-1)    *respinfo = (char)kXR_offline;
01974                      else if (S_ISDIR(mode)) *respinfo = (char)kXR_isDir;
01975                              else            *respinfo = (char)kXR_file;
01976                  }
01977          respinfo++;
01978         }
01979 
01980 // Return result
01981 //
01982    return Response.Send(argp->buff, respinfo-argp->buff);
01983 }
01984 
01985 /******************************************************************************/
01986 /*                               d o _ S y n c                                */
01987 /******************************************************************************/
01988   
01989 int XrdXrootdProtocol::do_Sync()
01990 {
01991    int rc;
01992    XrdXrootdFile *fp;
01993    XrdXrootdFHandle fh(Request.sync.fhandle);
01994 
01995 // Keep Statistics
01996 //
01997    UPSTATS(syncCnt);
01998 
01999 // Find the file object
02000 //
02001    if (!FTab || !(fp = FTab->Get(fh.handle)))
02002       return Response.Send(kXR_FileNotOpen,"sync does not refer to an open file");
02003 
02004 // Sync the file
02005 //
02006    rc = fp->XrdSfsp->sync();
02007    TRACEP(FS, "sync rc=" <<rc <<" fh=" <<fh.handle);
02008    if (SFS_OK != rc)
02009       return Response.Send(kXR_FSError, fp->XrdSfsp->error.getErrText());
02010 
02011 // Respond that all went well
02012 //
02013    return Response.Send();
02014 }
02015 
02016 /******************************************************************************/
02017 /*                           d o _ T r u n c a t e                            */
02018 /******************************************************************************/
02019   
02020 int XrdXrootdProtocol::do_Truncate()
02021 {
02022    XrdXrootdFile *fp;
02023    XrdXrootdFHandle fh(Request.truncate.fhandle);
02024    long long theOffset;
02025    int rc;
02026 
02027 // Unmarshall the data
02028 //
02029    n2hll(Request.truncate.offset, theOffset);
02030 
02031 // Check if this is a truncate for an open file (no path given)
02032 //
02033    if (!Request.header.dlen)
02034       {
02035        // Update misc stats count
02036        //
02037           UPSTATS(miscCnt);
02038 
02039       // Find the file object
02040       //
02041          if (!FTab || !(fp = FTab->Get(fh.handle)))
02042             return Response.Send(kXR_FileNotOpen,
02043                                      "trunc does not refer to an open file");
02044 
02045      // Truncate the file
02046      //
02047         rc = fp->XrdSfsp->truncate(theOffset);
02048         TRACEP(FS, "trunc rc=" <<rc <<" sz=" <<theOffset <<" fh=" <<fh.handle);
02049         if (SFS_OK != rc)
02050            return Response.Send(kXR_FSError, fp->XrdSfsp->error.getErrText());
02051 
02052    } else {
02053 
02054        XrdOucErrInfo myError(Link->ID);
02055        const char *opaque;
02056 
02057     // Verify the path and extract out the opaque information
02058     //
02059        if (rpCheck(argp->buff,&opaque)) return rpEmsg("Truncating",argp->buff);
02060        if (!Squash(argp->buff))         return vpEmsg("Truncating",argp->buff);
02061 
02062     // Preform the actual function
02063     //
02064        rc = osFS->truncate(argp->buff, (XrdSfsFileOffset)theOffset, myError,
02065                            CRED, opaque);
02066        TRACEP(FS, "rc=" <<rc <<" trunc " <<theOffset <<' ' <<argp->buff);
02067        if (SFS_OK != rc) return fsError(rc, myError);
02068    }
02069 
02070 // Respond that all went well
02071 //
02072    return Response.Send();
02073 }
02074   
02075 /******************************************************************************/
02076 /*                              d o _ W r i t e                               */
02077 /******************************************************************************/
02078   
02079 int XrdXrootdProtocol::do_Write()
02080 {
02081    int retc, pathID;
02082    XrdXrootdFHandle fh(Request.write.fhandle);
02083    numWrites++;
02084 
02085 // Unmarshall the data
02086 //
02087    myIOLen  = Request.header.dlen;
02088               n2hll(Request.write.offset, myOffset);
02089    pathID   = static_cast<int>(Request.write.pathid);
02090 
02091 // Find the file object
02092 //
02093    if (!FTab || !(myFile = FTab->Get(fh.handle)))
02094       {if (argp) return do_WriteNone();
02095        Response.Send(kXR_FileNotOpen,"write does not refer to an open file");
02096        return Link->setEtext("write protcol violation");
02097       }
02098 
02099 // If we are monitoring, insert a write entry
02100 //
02101    if (monIO && Monitor) Monitor->Add_wr(myFile->FileID, Request.write.dlen,
02102                                          Request.write.offset);
02103 
02104 // If zero length write, simply return
02105 //
02106    TRACEP(FS, "fh=" <<fh.handle <<" write " <<myIOLen <<'@' <<myOffset);
02107    if (myIOLen <= 0) return Response.Send();
02108 
02109 // See if an alternate path is required
02110 //
02111    if (pathID) return do_Offload(pathID, 1);
02112 
02113 // If we are in async mode, schedule the write to occur asynchronously
02114 //
02115    if (myFile->AsyncMode && !as_syncw)
02116       {if (myStalls > as_maxstalls) myStalls--;
02117           else if (myIOLen >= as_miniosz && Link->UseCnt() < as_maxperlnk)
02118                   {if ((retc = aio_Write()) != -EAGAIN)
02119                       {if (retc == -EIO) return do_WriteNone();
02120                           else return retc;
02121                       }
02122                   }
02123        SI->AsyncRej++;
02124       }
02125 
02126 // Just to the i/o now
02127 //
02128    myFile->writeCnt += myIOLen; // Optimistically correct
02129    return do_WriteAll();
02130 }
02131   
02132 /******************************************************************************/
02133 /*                           d o _ W r i t e A l l                            */
02134 /******************************************************************************/
02135 
02136 // myFile   = file to be written
02137 // myOffset = Offset at which to write
02138 // myIOLen  = Number of bytes to read from socket and write to file
02139   
02140 int XrdXrootdProtocol::do_WriteAll()
02141 {
02142    int rc, Quantum = (myIOLen > maxBuffsz ? maxBuffsz : myIOLen);
02143 
02144 // Make sure we have a large enough buffer
02145 //
02146    if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
02147       {if ((rc = getBuff(0, Quantum)) <= 0) return rc;}
02148       else if (hcNow < hcNext) hcNow++;
02149 
02150 // Now write all of the data (XrdXrootdProtocol.C defines getData())
02151 //
02152    while(myIOLen > 0)
02153         {if ((rc = getData("data", argp->buff, Quantum)))
02154             {if (rc > 0) 
02155                 {Resume = &XrdXrootdProtocol::do_WriteCont;
02156                  myBlast = Quantum;
02157                  myStalls++;
02158                 }
02159              return rc;
02160             }
02161          if (myFile->XrdSfsp->write(myOffset, argp->buff, Quantum) < 0)
02162             {myIOLen  = myIOLen-Quantum;
02163              return do_WriteNone();
02164             }
02165          myOffset += Quantum; myIOLen -= Quantum;
02166          if (myIOLen < Quantum) Quantum = myIOLen;
02167         }
02168 
02169 // All done
02170 //
02171    return Response.Send();
02172 }
02173 
02174 /******************************************************************************/
02175 /*                          d o _ W r i t e C o n t                           */
02176 /******************************************************************************/
02177 
02178 // myFile   = file to be written
02179 // myOffset = Offset at which to write
02180 // myIOLen  = Number of bytes to read from socket and write to file
02181 // myBlast  = Number of bytes already read from the socket
02182   
02183 int XrdXrootdProtocol::do_WriteCont()
02184 {
02185 
02186 // Write data that was finaly finished comming in
02187 //
02188    if (myFile->XrdSfsp->write(myOffset, argp->buff, myBlast) < 0)
02189       {myIOLen  = myIOLen-myBlast;
02190        return do_WriteNone();
02191       }
02192     myOffset += myBlast; myIOLen -= myBlast;
02193 
02194 // See if we need to finish this request in the normal way
02195 //
02196    if (myIOLen > 0) return do_WriteAll();
02197    return Response.Send();
02198 }
02199   
02200 /******************************************************************************/
02201 /*                          d o _ W r i t e N o n e                           */
02202 /******************************************************************************/
02203   
02204 int XrdXrootdProtocol::do_WriteNone()
02205 {
02206    int rlen, blen = (myIOLen > argp->bsize ? argp->bsize : myIOLen);
02207 
02208 // Discard any data being transmitted
02209 //
02210    TRACEP(REQ, "discarding " <<myIOLen <<" bytes");
02211    while(myIOLen > 0)
02212         {rlen = Link->Recv(argp->buff, blen, readWait);
02213          if (rlen  < 0) return Link->setEtext("link read error");
02214          myIOLen -= rlen;
02215          if (rlen < blen) 
02216             {myBlen   = 0;
02217              Resume   = &XrdXrootdProtocol::do_WriteNone;
02218              return 1;
02219             }
02220          if (myIOLen < blen) blen = myIOLen;
02221         }
02222 
02223 // Send our the error message and return
02224 //
02225    return Response.Send(kXR_FSError, myFile->XrdSfsp->error.getErrText());
02226 }
02227   
02228 /******************************************************************************/
02229 /*                       U t i l i t y   M e t h o d s                        */
02230 /******************************************************************************/
02231 /******************************************************************************/
02232 /*                               f s E r r o r                                */
02233 /******************************************************************************/
02234   
02235 int XrdXrootdProtocol::fsError(int rc, XrdOucErrInfo &myError)
02236 {
02237    int ecode;
02238    const char *eMsg = myError.getErrText(ecode);
02239 
02240 // Process standard errors
02241 //
02242    if (rc == SFS_ERROR)
02243       {SI->errorCnt++;
02244        rc = mapError(ecode);
02245        return Response.Send((XErrorCode)rc, eMsg);
02246       }
02247 
02248 // Process the redirection (error msg is host:port)
02249 //
02250    if (rc == SFS_REDIRECT)
02251       {SI->redirCnt++;
02252        if (ecode <= 0) ecode = (ecode ? -ecode : Port);
02253        TRACEI(REDIR, Response.ID() <<"redirecting to " << eMsg <<':' <<ecode);
02254        return Response.Send(kXR_redirect, ecode, eMsg);
02255       }
02256 
02257 // Process the deferal. We also synchronize sending the deferal response with
02258 // sending the actual defered response by calling Done() in the callback object.
02259 // This allows the requestor of he callback know that we actually send the
02260 // kXR_waitresp to the end client and avoid violating time causality.
02261 //
02262    if (rc == SFS_STARTED)
02263       {SI->stallCnt++;
02264        if (ecode <= 0) ecode = 1800;
02265        TRACEI(STALL, Response.ID() <<"delaying client up to " <<ecode <<" sec");
02266        rc = Response.Send(kXR_waitresp, ecode, eMsg);
02267        if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
02268        return (rc ? rc : 1);
02269       }
02270 
02271 // Process the data response
02272 //
02273    if (rc == SFS_DATA)
02274       {if (ecode) return Response.Send((void *)eMsg, ecode);
02275           else    return Response.Send();
02276       }
02277 
02278 // Process the deferal
02279 //
02280    if (rc >= SFS_STALL)
02281       {SI->stallCnt++;
02282        TRACEI(STALL, Response.ID() <<"stalling client for " <<rc <<" sec");
02283        return (rc = Response.Send(kXR_wait, rc, eMsg)) ? rc : 1;
02284       }
02285 
02286 // Unknown conditions, report it
02287 //
02288    {char buff[32];
02289     SI->errorCnt++;
02290     sprintf(buff, "%d", rc);
02291     eDest.Emsg("Xeq", "Unknown error code", buff, eMsg);
02292     return Response.Send(kXR_ServerError, eMsg);
02293    }
02294 }
02295   
02296 /******************************************************************************/
02297 /*                               g e t B u f f                                */
02298 /******************************************************************************/
02299   
02300 int XrdXrootdProtocol::getBuff(const int isRead, int Quantum)
02301 {
02302 
02303 // Check if we need to really get a new buffer
02304 //
02305    if (!argp || Quantum > argp->bsize) hcNow = hcPrev;
02306       else if (Quantum >= halfBSize || hcNow-- > 0) return 1;
02307               else if (hcNext >= hcMax) hcNow = hcMax;
02308                       else {int tmp = hcPrev;
02309                             hcNow   = hcNext;
02310                             hcPrev  = hcNext;
02311                             hcNext  = tmp+hcNext;
02312                            }
02313 
02314 // Get a new buffer
02315 //
02316    if (argp) BPool->Release(argp);
02317    if ((argp = BPool->Obtain(Quantum))) halfBSize = argp->bsize >> 1;
02318       else return Response.Send(kXR_NoMemory, (isRead ?
02319                                 "insufficient memory to read file" :
02320                                 "insufficient memory to write file"));
02321 
02322 // Success
02323 //
02324    return 1;
02325 }
02326 
02327 /******************************************************************************/
02328 /*                              m a p E r r o r                               */
02329 /******************************************************************************/
02330   
02331 int XrdXrootdProtocol::mapError(int rc)
02332 {
02333     if (rc < 0) rc = -rc;
02334     switch(rc)
02335        {case ENOENT:       return kXR_NotFound;
02336         case EPERM:        return kXR_NotAuthorized;
02337         case EACCES:       return kXR_NotAuthorized;
02338         case EIO:          return kXR_IOError;
02339         case ENOMEM:       return kXR_NoMemory;
02340         case ENOBUFS:      return kXR_NoMemory;
02341         case ENOSPC:       return kXR_NoSpace;
02342         case ENAMETOOLONG: return kXR_ArgTooLong;
02343         case ENETUNREACH:  return kXR_noserver;
02344         case ENOTBLK:      return kXR_NotFile;
02345         case EISDIR:       return kXR_isDirectory;
02346         case EEXIST:       return kXR_InvalidRequest;
02347         case ETXTBSY:      return kXR_inProgress;
02348         default:           return kXR_FSError;
02349        }
02350 }
02351 
02352 /******************************************************************************/
02353 /*                               m a p M o d e                                */
02354 /******************************************************************************/
02355 
02356 #define Map_Mode(x,y) if (Mode & kXR_ ## x) newmode |= S_I ## y
02357 
02358 int XrdXrootdProtocol::mapMode(int Mode)
02359 {
02360    int newmode = 0;
02361 
02362 // Map the mode in the obvious way
02363 //
02364    Map_Mode(ur, RUSR); Map_Mode(uw, WUSR);  Map_Mode(ux, XUSR);
02365    Map_Mode(gr, RGRP); Map_Mode(gw, WGRP);  Map_Mode(gx, XGRP);
02366    Map_Mode(or, ROTH);                      Map_Mode(ox, XOTH);
02367 
02368 // All done
02369 //
02370    return newmode;
02371 }
02372   
02373 /******************************************************************************/
02374 /*                               r p C h e c k                                */
02375 /******************************************************************************/
02376   
02377 int XrdXrootdProtocol::rpCheck(char *fn, const char **opaque)
02378 {
02379    char *cp;
02380 
02381    if (*fn != '/') return 1;
02382 
02383    if (!(cp = index(fn, '?'))) *opaque = 0;
02384       else {*cp = '\0'; *opaque = cp+1;
02385             if (!**opaque) *opaque = 0;
02386            }
02387 
02388    while ((cp = index(fn, '/')))
02389          {fn = cp+1;
02390           if (fn[0] == '.' && fn[1] == '.' && fn[2] == '/') return 1;
02391          }
02392    return 0;
02393 }
02394   
02395 /******************************************************************************/
02396 /*                                r p E m s g                                 */
02397 /******************************************************************************/
02398   
02399 int XrdXrootdProtocol::rpEmsg(const char *op, char *fn)
02400 {
02401    char buff[2048];
02402    snprintf(buff,sizeof(buff)-1,"%s relative path '%s' is disallowed.",op,fn);
02403    buff[sizeof(buff)-1] = '\0';
02404    return Response.Send(kXR_NotAuthorized, buff);
02405 }
02406  
02407 /******************************************************************************/
02408 /*                                S q u a s h                                 */
02409 /******************************************************************************/
02410   
02411 int XrdXrootdProtocol::Squash(char *fn)
02412 {
02413    char *ofn, *ifn = fn;
02414 
02415    while(*ifn)
02416         {if (*ifn == '/')
02417             if (*(ifn+1) == '/'
02418             || (*(ifn+1) == '.' && *(ifn+1) && *(ifn+2) == '/')) break;
02419          ifn++;
02420         }
02421 
02422    if (!*ifn) return XPList.Validate(fn, ifn-fn);
02423 
02424    ofn = ifn;
02425    while(*ifn) {*ofn = *ifn++;
02426                 while(*ofn == '/')
02427                    {while(*ifn == '/') ifn++;
02428                     if (ifn[0] == '.' && ifn[1] == '/') ifn += 2;
02429                        else break;
02430                    }
02431                 ofn++;
02432                }
02433    *ofn = '\0';
02434 
02435    return XPList.Validate(fn, ofn-fn);
02436 }
02437 
02438 /******************************************************************************/
02439 /*                               S t a t G e n                                */
02440 /******************************************************************************/
02441   
02442 #define XRDXROOTD_STAT_CLASSNAME XrdXrootdProtocol
02443 #include "XrdXrootd/XrdXrootdStat.icc"
02444 
02445 /******************************************************************************/
02446 /*                                v p E m s g                                 */
02447 /******************************************************************************/
02448   
02449 int XrdXrootdProtocol::vpEmsg(const char *op, char *fn)
02450 {
02451    char buff[2048];
02452    snprintf(buff,sizeof(buff)-1,"%s path '%s' is disallowed.",op,fn);
02453    buff[sizeof(buff)-1] = '\0';
02454    return Response.Send(kXR_NotAuthorized, buff);
02455 }

Generated on Tue Jul 5 14:47:04 2011 for ROOT_528-00b_version by  doxygen 1.5.1