#ifndef __XRDSSIRESPONDER_HH__
#define __XRDSSIRESPONDER_HH__
/******************************************************************************/
/* */
/* X r d S s i R e s p o n d e r . h h */
/* */
/* (c) 2013 by the Board of Trustees of the Leland Stanford, Jr., University */
/* 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 "XrdSsi/XrdSsiRequest.hh"
//-----------------------------------------------------------------------------
//! The XrdSsiResponder.hh class provides a request processing object a way to
//! respond to a request. It is a companion (friend) class of XrdSsiRequest.
//! This class is only practically meaningful server-side.
//!
//! Any class that needs to post a response, release a request buffer or post
//! stream data to the request object should inherit this class and use its
//! methods to get access to the request object. Typically, a task class that
//! is created by XrdSsiService::Execute() to handle the request would inherit
//! this class so it can respond. The object that wants to post a response must
//! first call BindRequest() to establish the request-responder association.
//!
//! When the XrdSsiResponder::SetResponse() method is called to post a response
//! the request object's ProcessResponse() method is called. Ownership of the
//! request object does not revert back to the object's creator until the
//! XrdSsiRequest::Finished() method returns. That method first calls
//! XrdSsiResponder::Finished() to break the request-responder association and
//! reclaim any response data buffer or stream resource before it gives up
//! control of the request object. This means you must provide an implementation
//! To the Finished() method defined here.
//!
//! Once Finished() is called you must call UnBindRequest() when you are
//! actually through referencing the request object. While that is true most
//! of the time, it may not be so when an async cancellation occurs (i.e.
//! you may need to defer release of the request object). Note that should
//! you delete this object before calling UnBindRequest(), the responder
//! object is forcibly unbound from the request.
//-----------------------------------------------------------------------------
class XrdSsiStream;
class XrdSsiResponder
{
public:
friend class XrdSsiRequest;
friend class XrdSsiRRAgent;
//-----------------------------------------------------------------------------
//! The maximum amount of metadata+data (i.e. the sum of two blen arguments in
//! SetMetadata() and and SetResponse(const char *buff, int blen), respectively)
//! that may be directly sent to the client without the SSI framework converting
//! the data buffer response into a stream response.
//-----------------------------------------------------------------------------
static const int MaxDirectXfr = 2097152; //< Max (metadata+data) direct xfr
//-----------------------------------------------------------------------------
//! Take ownership of a request object by binding the request object to a
//! responder object. This method must be called by the responder before
//! posting any responses.
//!
//! @param rqstR reference to the request object.
//-----------------------------------------------------------------------------
void BindRequest(XrdSsiRequest &rqstR);
//-----------------------------------------------------------------------------
//! Unbind this responder from the request object it is bound to. Upon return
//! ownership of the associated request object reverts back to the creator of
//! the object who is responsible for deleting or recycling the request object.
//! UnBindRequest() is also called when the responder object is deleted.
//!
//! @return true Request successfully unbound.
//! false UnBindRequest already called or called prior to Finish().
//-----------------------------------------------------------------------------
bool UnBindRequest();
protected:
//-----------------------------------------------------------------------------
//! Send an alert message to the request. This is a convenience method that
//! avoids race conditions with Finished() so it is safe to use in all cases.
//! This is a server-side call. The service is responsible for creating a
//! RespInfoMsg object containing the message and supplying a RecycleMsg() method.
//!
//! @param aMsg reference to the message to be sent.
//-----------------------------------------------------------------------------
void Alert(XrdSsiRespInfoMsg &aMsg);
//-----------------------------------------------------------------------------
//! Notify the responder that a request either completed or was canceled. This
//! allows the responder to release any resources given to the request object
//! (e.g. data response buffer or a stream). This method is invoked when
//! XrdSsiRequest::Finished() is called by the client.
//!
//! @param rqstR reference to the object describing the request.
//! @param rInfo reference to the object describing the response.
//! @param cancel False -> the request/response interaction completed.
//! True -> the request/response interaction aborted because
//! of an error or the client requested that the
//! request be canceled.
//-----------------------------------------------------------------------------
virtual void Finished( XrdSsiRequest &rqstR,
const XrdSsiRespInfo &rInfo,
bool cancel=false) = 0;
//-----------------------------------------------------------------------------
//! Obtain the request data sent by a client.
//!
//! Note: This method is called with the object's recursive mutex unlocked!
//!
//! @param dlen holds the length of the request after the call.
//!
//! @return =0 No request data available, dlen has been set to zero.
//! @return !0 Pointer to the buffer holding the request, dlen has the length
//-----------------------------------------------------------------------------
char *GetRequest(int &dlen);
//-----------------------------------------------------------------------------
//! Release the request buffer of the request bound to this object. This method
//! duplicates the protected method of the same name in XrdSsiRequest and exists
//! here for calling safety and consistency relative to the responder.
//-----------------------------------------------------------------------------
void ReleaseRequestBuffer();
//-----------------------------------------------------------------------------
//! The following enums are returned by SetMetadata() and SetResponse() to
//! indicate ending status.
//-----------------------------------------------------------------------------
enum Status {wasPosted=0, //!< Success: The response was successfully posted
notPosted, //!< Failure: A request was not bound to this object
//!< or a response has already been posted
//!< or the metadata length was invalid
notActive //!< Failure: Request is no longer active
};
//-----------------------------------------------------------------------------
//! Set a pointer to metadata to be sent out-of-band ahead of the response.
//!
//! @param buff pointer to a buffer holding the metadata. The buffer must
//! remain valid until XrdSsiResponder::Finished() is called.
//! @param blen the length of the metadata in buff that is to be sent. It must
//! in the range 0 <= blen <= MaxMetaDataSZ.
//!
//! @return See Status enum for possible values.
//-----------------------------------------------------------------------------
static const int MaxMetaDataSZ = 2097152; //!< 2MB metadata limit
Status SetMetadata(const char *buff, int blen);
//-----------------------------------------------------------------------------
//! Set an error response for a request.
//!
//! @param eMsg the message describing the error. The message is copied to
//! private storage.
//! @param eNum the errno associated with the error.
//!
//! @return See Status enum for possible values.
//-----------------------------------------------------------------------------
Status SetErrResponse(const char *eMsg, int eNum);
//-----------------------------------------------------------------------------
//! Set a nil response for a request (used for sending only metadata).
//!
//! @return See Status enum for possible values.
//-----------------------------------------------------------------------------
inline Status SetNilResponse() {return SetResponse((const char *)0,0);}
//-----------------------------------------------------------------------------
//! Set a memory buffer containing data as the request response.
//!
//! @param buff pointer to a buffer holding the response. The buffer must
//! remain valid until XrdSsiResponder::Finished() is called.
//! @param blen the length of the response in buff that is to be sent.
//!
//! @return See Status enum for possible values.
//-----------------------------------------------------------------------------
Status SetResponse(const char *buff, int blen);
//-----------------------------------------------------------------------------
//! Set a file containing data as the response.
//!
//! @param fsize the size of the file containing the response.
//! @param fdnum the file descriptor of the open file.
//!
//! @return See Status enum for possible values.
//-----------------------------------------------------------------------------
Status SetResponse(long long fsize, int fdnum);
//-----------------------------------------------------------------------------
//! Set a stream object that is to provide data as the response.
//!
//! @param strmP pointer to stream object that is to be used to supply response
//! data. See XrdSsiStream for more details.
//!
//! @return See Status enum for possible values.
//-----------------------------------------------------------------------------
Status SetResponse(XrdSsiStream *strmP);
//-----------------------------------------------------------------------------
//! This class is meant to be inherited by an object that will actually posts
//! responses.
//-----------------------------------------------------------------------------
XrdSsiResponder();
//-----------------------------------------------------------------------------
//! Destructor is protected. You cannot use delete on a responder object, as it
//! is meant to be inherited by a class and not separately instantiated.
//-----------------------------------------------------------------------------
protected:
virtual ~XrdSsiResponder();
private:
// The spMutex protects the reqP pointer. It is a hiearchical mutex in that it
// may be obtained prior to obtaining the mutex protecting the request without
// fear of a deadlock (the reverse is not possible). If reqP is zero then
// this responder is not bound to a request.
//
XrdSsiMutex spMutex;
XrdSsiRequest *reqP;
long long rsvd1; // Reserved fields for extensions with ABI compliance
long long rsvd2;
long long rsvd3;
};
#endif