XrdCmsReq.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                          X r d C m s R e q . c c                           */
00004 /*                                                                            */
00005 /* (c) 2006 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010 
00011 //         $Id: XrdCmsReq.cc 31508 2009-12-02 19:11:01Z brun $
00012 
00013 // Original Version: 1.4 2007/07/31 02:25:16 abh
00014 
00015 const char *XrdCmsReqCVSID = "$Id: XrdCmsReq.cc 31508 2009-12-02 19:11:01Z brun $";
00016 
00017 #include <stdio.h>
00018 #include <unistd.h>
00019 #include <sys/stat.h>
00020 #include <sys/types.h>
00021 #include <sys/uio.h>
00022 #include <netinet/in.h>
00023 #include <inttypes.h>
00024   
00025 #include "XrdCms/XrdCmsNode.hh"
00026 #include "XrdCms/XrdCmsReq.hh"
00027 #include "XrdCms/XrdCmsRRQ.hh"
00028 #include "XrdCms/XrdCmsRTable.hh"
00029 #include "XrdCms/XrdCmsTrace.hh"
00030 #include "XrdSys/XrdSysError.hh"
00031 #include "XrdSys/XrdSysPlatform.hh"
00032 #include "XrdSys/XrdSysPthread.hh"
00033 
00034 #include "XProtocol/XProtocol.hh"
00035 #include "XProtocol/YProtocol.hh"
00036 
00037 using namespace XrdCms;
00038 
00039 /******************************************************************************/
00040 /*                        C o n s t r u c t o r   # 1                         */
00041 /******************************************************************************/
00042   
00043 XrdCmsReq::XrdCmsReq(XrdCmsNode *nP, unsigned int reqid, char adv)
00044 {
00045    NodeP   = nP;
00046    ReqID   = reqid;
00047    ReqNnum = nP->getSlot();
00048    ReqNins = nP->Inst();
00049    ReqAdv  = adv;
00050 }
00051 
00052 /******************************************************************************/
00053 /*                        C o n s t r u c t o r   # 2                         */
00054 /******************************************************************************/
00055   
00056 XrdCmsReq::XrdCmsReq(XrdCmsReq *Req, unsigned int rn)
00057 {
00058    NodeP   = 0;
00059    ReqID   = rn;
00060    ReqNnum = Req->ReqNnum;
00061    ReqNins = Req->ReqNins;
00062 }
00063 
00064 /******************************************************************************/
00065 /*                           R e p l y _ E r r o r                            */
00066 /******************************************************************************/
00067   
00068 void XrdCmsReq::Reply_Error(const char *emsg, int elen)
00069 {
00070 
00071 // Make sure that elen includes a null byte
00072 //
00073    if (!elen) elen = strlen(emsg)+1;
00074       else if (emsg[elen]) elen++;
00075 
00076 // Send off the reply
00077 //
00078    Reply(kYR_error, kYR_EINVAL, emsg, elen);
00079 }
00080  
00081 /******************************************************************************/
00082 /*                           R e p l y _ E r r o r                            */
00083 /******************************************************************************/
00084   
00085 void XrdCmsReq::Reply_Error(const char *ecode, const char *emsg, int elen)
00086 {
00087    unsigned int eval;
00088 
00089 // Translate the error name
00090 //
00091         if (!strcmp("ENOENT", ecode))       eval = kYR_ENOENT;
00092    else if (!strcmp("EPERM", ecode))        eval = kYR_EPERM;
00093    else if (!strcmp("EACCES", ecode))       eval = kYR_EACCES;
00094    else if (!strcmp("EIO", ecode))          eval = kYR_EIO;
00095    else if (!strcmp("ENOMEM", ecode))       eval = kYR_ENOMEM;
00096    else if (!strcmp("ENOSPC", ecode))       eval = kYR_ENOSPC;
00097    else if (!strcmp("ENAMETOOLONG", ecode)) eval = kYR_ENAMETOOLONG;
00098    else if (!strcmp("ENETUNREACH", ecode))  eval = kYR_ENETUNREACH;
00099    else if (!strcmp("ENOTBLK", ecode))      eval = kYR_ENOTBLK;
00100    else if (!strcmp("EISDIR", ecode))       eval = kYR_EISDIR;
00101    else                                     eval = kYR_EINVAL;
00102 
00103 // Make sure that elen includes a null byte
00104 //
00105    if (!elen) elen = strlen(emsg)+1;
00106       else if (emsg[elen]) elen++;
00107 
00108 // Send off the reply
00109 //
00110    Reply(kYR_error, eval, emsg, elen);
00111 }
00112 
00113 /******************************************************************************/
00114   
00115 void XrdCmsReq::Reply_Error(int ecode, const char *emsg, int elen)
00116 {
00117    unsigned int eval;
00118 
00119 // Translate the error name
00120 //
00121    switch(ecode)
00122          {case ENOENT:       eval = kYR_ENOENT;
00123           case EPERM:        eval = kYR_EPERM;
00124           case EACCES:       eval = kYR_EACCES;
00125           case EIO:          eval = kYR_EIO;
00126           case ENOMEM:       eval = kYR_ENOMEM;
00127           case ENOSPC:       eval = kYR_ENOSPC;
00128           case ENAMETOOLONG: eval = kYR_ENAMETOOLONG;
00129           case ENETUNREACH:  eval = kYR_ENETUNREACH;
00130           case ENOTBLK:      eval = kYR_ENOTBLK;
00131           case EISDIR:       eval = kYR_EISDIR;
00132           default:           eval = kYR_EINVAL;
00133          };
00134 
00135 // Make sure that elen includes a null byte
00136 //
00137    if (!elen) elen = strlen(emsg)+1;
00138       else if (emsg[elen]) elen++;
00139 
00140 // Send off the reply
00141 //
00142    Reply(kYR_error, eval, emsg, elen);
00143 }
00144 
00145 /******************************************************************************/
00146 /*                              R e p l y _ O K                               */
00147 /******************************************************************************/
00148   
00149 void XrdCmsReq::Reply_OK()
00150 {
00151 
00152 // Send off the reply (this object may be deleted so make a fast exit)
00153 //
00154    Reply(kYR_data, 0, "", 1);
00155 }
00156   
00157 /******************************************************************************/
00158   
00159 void XrdCmsReq::Reply_OK(const char *data, int dlen)
00160 {
00161 
00162 // Make sure that elen includes a null byte
00163 //
00164    if (!dlen) dlen = strlen(data)+1;
00165       else if (data[dlen]) dlen++;
00166 
00167 // Send off the reply (this object may be deleted so make a fast exit)
00168 //
00169    Reply(kYR_data, 0, data, dlen);
00170 }
00171  
00172 /******************************************************************************/
00173 
00174 void XrdCmsReq::Reply_OK(struct stat &buf)
00175 {
00176    char sbuff[256];
00177 
00178    Reply_OK(sbuff, StatGen(buf, sbuff));
00179 }
00180 
00181 /******************************************************************************/
00182 /*                        R e p l y _ R e d i r e c t                         */
00183 /******************************************************************************/
00184   
00185 void XrdCmsReq::Reply_Redirect(const char *sname, 
00186                                const char *lcgi, const char *ocgi)
00187 {
00188    char hbuff[256], *colon;
00189    const char *hP = hbuff;
00190    int hlen, Port;
00191 
00192 // Find the port number in the host name
00193 //
00194    if (!(colon = (char *) index(sname, ':'))) 
00195       {Port = 0;
00196        hP = sname;
00197       } else {
00198        Port = atoi(colon+1);
00199        hlen = colon-sname+1;
00200        if (hlen >= (int)sizeof(hbuff)) hlen = sizeof(hbuff);
00201        strlcpy(hbuff, sname, hlen);
00202       }
00203 
00204 // Send off the request
00205 //
00206    Reply_Redirect(hP, Port, lcgi, ocgi);
00207 }
00208 
00209 /******************************************************************************/
00210   
00211 void XrdCmsReq::Reply_Redirect(const char *sname, int Port,
00212                                const char *lcgi, const char *ocgi)
00213 {
00214    struct iovec iov[8];
00215    int iovnum, hlen = strlen(sname);
00216 
00217 // Fill out the iovec
00218 //
00219    iov[1].iov_base = (char *)sname;
00220    iov[1].iov_len  = strlen(sname);
00221    hlen = iov[1].iov_len;
00222 
00223 // Now we need to see if we have any cgi info to pass
00224 //
00225    if (!lcgi && !ocgi) iovnum = 2;
00226       else {if (ocgi)
00227                {iov[2].iov_base = (char *)"?";
00228                 iov[2].iov_len  = 1;
00229                 iov[3].iov_base = (char *)ocgi;
00230                 iov[3].iov_len  = strlen(ocgi);
00231                 hlen += iov[3].iov_len + 1;
00232                 if (lcgi)
00233                    {iov[4].iov_base = (char *)"?";
00234                     iov[4].iov_len  = 1;
00235                     iov[5].iov_base = (char *)lcgi;
00236                     iov[5].iov_len  = strlen(lcgi);
00237                     hlen += iov[5].iov_len + 1;
00238                           iovnum = 6;
00239                    } else iovnum = 4;
00240                } else {
00241                 iov[2].iov_base = (char *)"??";
00242                 iov[2].iov_len  = 2;
00243                 iov[3].iov_base = (char *)lcgi;
00244                 iov[3].iov_len  = strlen(lcgi);
00245                 hlen += iov[3].iov_len + 2;
00246                 iovnum = 4;
00247                }
00248            }
00249 
00250 // Make sure that last iov element and hlen includes the terminating null byte
00251 //
00252    iov[iovnum-1].iov_len++; hlen++;
00253 
00254 // Send off the reply
00255 //
00256    Reply(kYR_redirect, (unsigned int)Port, 0, hlen, iov, iovnum);
00257 }
00258 
00259 /******************************************************************************/
00260 /*                            R e p l y _ W a i t                             */
00261 /******************************************************************************/
00262   
00263 void XrdCmsReq::Reply_Wait(int sec)
00264 {
00265 
00266 // Send off the reply
00267 //
00268    Reply(kYR_wait, (unsigned int)sec, "", 1);
00269 }
00270 
00271 /******************************************************************************/
00272 /*                        R e p l y _ W a i t R e s p                         */
00273 /******************************************************************************/
00274   
00275 XrdCmsReq *XrdCmsReq::Reply_WaitResp(int sec)
00276 {
00277    static XrdSysMutex rnMutex;
00278    static unsigned int RequestNum = 0;
00279           unsigned int rnum;
00280           XrdCmsReq *newReq;
00281 
00282 // If this is already a waitresp object then we cannot do this again. So,
00283 // just return a null pointer indicating an invalid call.
00284 //
00285    if (!NodeP) return (XrdCmsReq *)0;
00286 
00287 // Generate a request number unless no reply is needed
00288 //
00289    if (ReqID)
00290       {rnMutex.Lock();
00291        RequestNum++;
00292        rnum = RequestNum;
00293        rnMutex.UnLock();
00294      } else rnum = 0;
00295 
00296 // Construct a new request object. This object will be used to actually effect
00297 // the reply. We need to do this because the server may disappear before we
00298 // actually reply. In which case the reply gets deep-sixed.
00299 //
00300    newReq = new XrdCmsReq(this, rnum);
00301 
00302 // Reply to the requestor mapping our ID to their ID
00303 //
00304    if (rnum)
00305       {
00306        Reply(kYR_waitresp, rnum);
00307       }
00308 
00309 // Return an object to affect an asynchronous reply
00310 //
00311    return newReq;
00312 }
00313 
00314 /******************************************************************************/
00315 /*                       P r i v a t e   M e t h o d s                        */
00316 /******************************************************************************/
00317   
00318 #define XRDXROOTD_STAT_CLASSNAME XrdCmsReq
00319 #include "XrdXrootd/XrdXrootdStat.icc"
00320 
00321 /******************************************************************************/
00322 /*                               n o R e p l y                                */
00323 /******************************************************************************/
00324   
00325 void XrdCmsReq::noReply()
00326 {
00327    static int nrNum = 255;
00328 
00329 // We always issue a message about double object use otherwise issue warning
00330 // as this is indicative of an improper configuration.
00331 //
00332    if (ReqNnum < 0)
00333       Say.Emsg("Req", "Attempted reply to twice to a 2way async request.");
00334       else {nrNum++;
00335             if (!(nrNum & 255)) Say.Emsg("Req", 
00336                                 "Attempted reply to a 1way request; "
00337                                 "probably incorrect ofs forward directive.");
00338            }
00339 }
00340 
00341 /******************************************************************************/
00342 /*                                 R e p l y                                  */
00343 /******************************************************************************/
00344   
00345 void XrdCmsReq::Reply(       int    respCode, unsigned int respVal,
00346                       const  char  *respData, int respLen,
00347                       struct iovec *iov,      int iovnum)
00348 {
00349    EPNAME("Reply");
00350    CmsResponse Resp = {{ReqID, respCode, 0, 0}, htonl(respVal)};
00351    struct iovec myiov[2], *iovP;
00352    XrdCmsNode *nP;
00353 
00354 // Set the actual data length
00355 //
00356    Resp.Hdr.datalen = htons(static_cast<short>(respLen+sizeof(int)));
00357 
00358 // Complete iovec
00359 //
00360    if (iov)
00361       { iov->iov_base = (char *)&Resp;
00362         iov->iov_len  = sizeof(Resp);
00363         iovP = iov;
00364       } else {
00365        myiov[0].iov_base = (char *)&Resp;
00366        myiov[0].iov_len  = sizeof(Resp);
00367        if (respData)
00368           {myiov[1].iov_base = (char *)respData;
00369            myiov[1].iov_len  = respLen;
00370            iovnum = 2;
00371           } else iovnum = 1;
00372        iovP = myiov;
00373       }
00374 
00375 // Reply format differs depending on whether this is a sync or async reply
00376 //
00377    if (NodeP)
00378       {if (ReqID) NodeP->Send(iovP, iovnum);
00379           else noReply();
00380        return;
00381       }
00382 
00383 // Async replies are more complicated here since we must find the server using
00384 // a logical address that may no longer be valid.
00385 //
00386    RTable.Lock();
00387    if ((nP = RTable.Find(ReqNnum, ReqNins)))
00388       {Resp.Hdr.modifier |= CmsResponse::kYR_async;
00389        nP->Send(iovP, iovnum);
00390       }
00391       else {DEBUG("Async resp " <<ReqID <<" discarded; server gone");}
00392    RTable.UnLock();
00393 
00394 // Only one async response is allowed. Mark this object unusable
00395 //
00396    ReqID   = 0;
00397    ReqNnum = -1;
00398 }

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