/******************************************************************************/ /* */ /* X r d C m s R e q . c c */ /* */ /* (c) 2006 by the Board of Trustees of the Leland Stanford, Jr., University */ /* All Rights Reserved */ /* Produced by Andrew Hanushevsky for Stanford University under contract */ /* DE-AC02-76-SFO0515 with the Department of Energy */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ #include #include #include #include #include #include #include #include "XrdCms/XrdCmsNode.hh" #include "XrdCms/XrdCmsReq.hh" #include "XrdCms/XrdCmsRRQ.hh" #include "XrdCms/XrdCmsRTable.hh" #include "XrdCms/XrdCmsTrace.hh" #include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysPlatform.hh" #include "XrdSys/XrdSysPthread.hh" #include "XProtocol/XProtocol.hh" #include "XProtocol/YProtocol.hh" using namespace XrdCms; /******************************************************************************/ /* C o n s t r u c t o r # 1 */ /******************************************************************************/ XrdCmsReq::XrdCmsReq(XrdCmsNode *nP, unsigned int reqid, char adv) { NodeP = nP; ReqID = reqid; ReqNnum = nP->getSlot(); ReqNins = nP->Inst(); ReqAdv = adv; } /******************************************************************************/ /* C o n s t r u c t o r # 2 */ /******************************************************************************/ XrdCmsReq::XrdCmsReq(XrdCmsReq *Req, unsigned int rn) { NodeP = 0; ReqID = rn; ReqNnum = Req->ReqNnum; ReqNins = Req->ReqNins; ReqAdv = 0; } /******************************************************************************/ /* R e p l y _ E r r o r */ /******************************************************************************/ void XrdCmsReq::Reply_Error(const char *emsg, int elen) { // Make sure that elen includes a null byte // if (!elen) elen = strlen(emsg)+1; else if (emsg[elen]) elen++; // Send off the reply // Reply(kYR_error, kYR_EINVAL, emsg, elen); } /******************************************************************************/ /* R e p l y _ E r r o r */ /******************************************************************************/ void XrdCmsReq::Reply_Error(const char *ecode, const char *emsg, int elen) { unsigned int eval; // Translate the error name // if (!strcmp("ENOENT", ecode)) eval = kYR_ENOENT; else if (!strcmp("EPERM", ecode)) eval = kYR_EPERM; else if (!strcmp("EACCES", ecode)) eval = kYR_EACCES; else if (!strcmp("EIO", ecode)) eval = kYR_EIO; else if (!strcmp("ENOMEM", ecode)) eval = kYR_ENOMEM; else if (!strcmp("ENOSPC", ecode)) eval = kYR_ENOSPC; else if (!strcmp("ENAMETOOLONG", ecode)) eval = kYR_ENAMETOOLONG; else if (!strcmp("ENETUNREACH", ecode)) eval = kYR_ENETUNREACH; else if (!strcmp("ENOTBLK", ecode)) eval = kYR_ENOTBLK; else if (!strcmp("EISDIR", ecode)) eval = kYR_EISDIR; else eval = kYR_EINVAL; // Make sure that elen includes a null byte // if (!elen) elen = strlen(emsg)+1; else if (emsg[elen]) elen++; // Send off the reply // Reply(kYR_error, eval, emsg, elen); } /******************************************************************************/ void XrdCmsReq::Reply_Error(int ecode, const char *emsg, int elen) { unsigned int eval; // Translate the error name // switch(ecode) {case ENOENT: eval = kYR_ENOENT; break; case EPERM: eval = kYR_EPERM; break; case EACCES: eval = kYR_EACCES; break; case EIO: eval = kYR_EIO; break; case ENOMEM: eval = kYR_ENOMEM; break; case ENOSPC: eval = kYR_ENOSPC; break; case ENAMETOOLONG: eval = kYR_ENAMETOOLONG; break; case ENETUNREACH: eval = kYR_ENETUNREACH; break; case ENOTBLK: eval = kYR_ENOTBLK; break; case EISDIR: eval = kYR_EISDIR; break; default: eval = kYR_EINVAL; break; }; // Make sure that elen includes a null byte // if (!elen) elen = strlen(emsg)+1; else if (emsg[elen]) elen++; // Send off the reply // Reply(kYR_error, eval, emsg, elen); } /******************************************************************************/ /* R e p l y _ O K */ /******************************************************************************/ void XrdCmsReq::Reply_OK() { // Send off the reply (this object may be deleted so make a fast exit) // Reply(kYR_data, 0, "", 1); } /******************************************************************************/ void XrdCmsReq::Reply_OK(const char *data, int dlen) { // Make sure that elen includes a null byte // if (!dlen) dlen = strlen(data)+1; else if (data[dlen]) dlen++; // Send off the reply (this object may be deleted so make a fast exit) // Reply(kYR_data, 0, data, dlen); } /******************************************************************************/ void XrdCmsReq::Reply_OK(struct stat &buf) { char sbuff[256]; Reply_OK(sbuff, StatGen(buf, sbuff)); } /******************************************************************************/ /* R e p l y _ R e d i r e c t */ /******************************************************************************/ void XrdCmsReq::Reply_Redirect(const char *sname, const char *lcgi, const char *ocgi) { char hbuff[256], *colon; const char *hP = hbuff; int hlen, Port; // Find the port number in the host name // if (!(colon = (char *) index(sname, ':'))) {Port = 0; hP = sname; } else { Port = atoi(colon+1); hlen = colon-sname+1; if (hlen >= (int)sizeof(hbuff)) hlen = sizeof(hbuff); strlcpy(hbuff, sname, hlen); } // Send off the request // Reply_Redirect(hP, Port, lcgi, ocgi); } /******************************************************************************/ void XrdCmsReq::Reply_Redirect(const char *sname, int Port, const char *lcgi, const char *ocgi) { struct iovec iov[8]; int iovnum, hlen = strlen(sname); // Fill out the iovec // iov[1].iov_base = (char *)sname; iov[1].iov_len = strlen(sname); hlen = iov[1].iov_len; // Now we need to see if we have any cgi info to pass // if (!lcgi && !ocgi) iovnum = 2; else {if (ocgi) {iov[2].iov_base = (char *)"?"; iov[2].iov_len = 1; iov[3].iov_base = (char *)ocgi; iov[3].iov_len = strlen(ocgi); hlen += iov[3].iov_len + 1; if (lcgi) {iov[4].iov_base = (char *)"?"; iov[4].iov_len = 1; iov[5].iov_base = (char *)lcgi; iov[5].iov_len = strlen(lcgi); hlen += iov[5].iov_len + 1; iovnum = 6; } else iovnum = 4; } else { iov[2].iov_base = (char *)"??"; iov[2].iov_len = 2; iov[3].iov_base = (char *)lcgi; iov[3].iov_len = strlen(lcgi); hlen += iov[3].iov_len + 2; iovnum = 4; } } // Make sure that last iov element and hlen includes the terminating null byte // iov[iovnum-1].iov_len++; hlen++; // Send off the reply // Reply(kYR_redirect, (unsigned int)Port, 0, hlen, iov, iovnum); } /******************************************************************************/ /* R e p l y _ W a i t */ /******************************************************************************/ void XrdCmsReq::Reply_Wait(int sec) { // Send off the reply // Reply(kYR_wait, (unsigned int)sec, "", 1); } /******************************************************************************/ /* R e p l y _ W a i t R e s p */ /******************************************************************************/ XrdCmsReq *XrdCmsReq::Reply_WaitResp(int sec) { static XrdSysMutex rnMutex; static unsigned int RequestNum = 0; unsigned int rnum; XrdCmsReq *newReq; // If this is already a waitresp object then we cannot do this again. So, // just return a null pointer indicating an invalid call. // if (!NodeP) return (XrdCmsReq *)0; // Generate a request number unless no reply is needed // if (ReqID) {rnMutex.Lock(); RequestNum++; rnum = RequestNum; rnMutex.UnLock(); } else rnum = 0; // Construct a new request object. This object will be used to actually effect // the reply. We need to do this because the server may disappear before we // actually reply. In which case the reply gets deep-sixed. // newReq = new XrdCmsReq(this, rnum); // Reply to the requestor mapping our ID to their ID // if (rnum) { Reply(kYR_waitresp, rnum); } // Return an object to affect an asynchronous reply // return newReq; } /******************************************************************************/ /* P r i v a t e M e t h o d s */ /******************************************************************************/ #define XRDXROOTD_STAT_CLASSNAME XrdCmsReq #include "XrdXrootd/XrdXrootdStat.icc" /******************************************************************************/ /* n o R e p l y */ /******************************************************************************/ void XrdCmsReq::noReply() { static int nrNum = 255; // We always issue a message about double object use otherwise issue warning // as this is indicative of an improper configuration. // if (ReqNnum < 0) Say.Emsg("Req", "Attempted reply to twice to a 2way async request."); else {nrNum++; if (!(nrNum & 255)) Say.Emsg("Req", "Attempted reply to a 1way request; " "probably incorrect ofs forward directive."); } } /******************************************************************************/ /* R e p l y */ /******************************************************************************/ void XrdCmsReq::Reply( int respCode, unsigned int respVal, const char *respData, int respLen, struct iovec *iov, int iovnum) { EPNAME("Reply"); CmsResponse Resp = {{ReqID, (kXR_char)respCode, 0, 0}, htonl(respVal)}; struct iovec myiov[2], *iovP; XrdCmsNode *nP; // Set the actual data length // Resp.Hdr.datalen = htons(static_cast(respLen+sizeof(int))); // Complete iovec // if (iov) { iov->iov_base = (char *)&Resp; iov->iov_len = sizeof(Resp); iovP = iov; } else { myiov[0].iov_base = (char *)&Resp; myiov[0].iov_len = sizeof(Resp); if (respData) {myiov[1].iov_base = (char *)respData; myiov[1].iov_len = respLen; iovnum = 2; } else iovnum = 1; iovP = myiov; } // Reply format differs depending on whether this is a sync or async reply // if (NodeP) {if (ReqID) NodeP->Send(iovP, iovnum); else noReply(); return; } // Async replies are more complicated here since we must find the server using // a logical address that may no longer be valid. // RTable.Lock(); if ((nP = RTable.Find(ReqNnum, ReqNins))) {Resp.Hdr.modifier |= CmsResponse::kYR_async; nP->Send(iovP, iovnum); } else {DEBUG("Async resp " <