28 #include "XrdOuc/XrdOucStream.hh"
30 #include "XrdVersion.hh"
31 #include "Xrd/XrdBuffer.hh"
32 #include "Xrd/XrdScheduler.hh"
59 "xproofd protocol anchor");
81 #define XPDCOND(n,ns) ((n == -1 && ns == -1) || (n > 0 && n >= ns))
84 #define XPDSETSTRING(n,ns,c,s) \
85 { if (XPDCOND(n,ns)) { \
86 SafeFree(c); c = strdup(s.c_str()); ns = n; }}
89 #ifndef XPDADOPTSTRING
90 #define XPDADOPTSTRING(n,ns,c,s) \
92 XPDSETSTRING(n, ns, t, s); \
93 if (t && strlen(t)) { \
100 #define XPDSETINT(n,ns,i,s) \
101 { if (XPDCOND(n,ns)) { \
102 i = strtol(s.c_str(),0,10); ns = n; }}
112 typedef struct ResetCtrlcGuard {
116 ~ResetCtrlcGuard() {
if (xpd && type !=
kXP_ctrlc) xpd->ResetCtrlC(); }
124 XrdProofdProtCfg(
const char *cfg,
XrdSysError *edest = 0);
132 XrdProofdProtCfg::XrdProofdProtCfg(
const char *cfg,
XrdSysError *edest)
136 RegisterDirectives();
142 void XrdProofdProtCfg::RegisterDirectives()
152 char *val, XrdOucStream *cfg,
bool)
156 XrdOucString port(val);
157 if (d->
fName ==
"xrd.protocol") {
158 port = cfg->GetWord();
159 port.replace(
"xproofd:",
"");
160 }
else if (d->
fName !=
"port") {
163 if (port.length() > 0) {
164 fPort = strtol(port.c_str(), 0, 10);
170 #if (ROOTXRDVERS >= 300030000)
188 return (XrdProtocol *)0;
201 XrdProofdProtCfg pcfg(pi->ConfigFN, pi->eDest);
203 XrdProofdTrace =
new XrdOucTrace(pi->eDest);
206 if (pcfg.fPort > 0) {
219 : XrdProtocol(
"xproofd protocol handler"), fProtLink(this)
228 fStdErrFD = (pi && pi->eDest) ? pi->eDest->baseFD() : fileno(stderr);
239 XPDLOC(ALL,
"Protocol::Response")
255 XPDLOC(ALL,
"Protocol::GetNewResponse")
265 msg +=
" new capacity: ";
273 msg +=
"; new size: ";
278 TRACE(XERR,
"wrong sid: "<<sid);
293 XPDLOC(ALL,
"Protocol::Match")
295 struct ClientInitHandShake hsdata;
296 char *hsbuff = (
char *)&hsdata;
298 static hs_response_t hsresp = {0, 0, kXR_int32(htonl(
XPROOFD_VERSBIN)), 0};
302 TRACE(HDBG,
"enter");
306 if ((dlen = lp->Peek(hsbuff,
sizeof(hsdata),
fgReadWait)) !=
sizeof(hsdata)) {
307 if (dlen <= 0) lp->setEtext(
"Match: handshake not received");
310 hsdata.first = ntohl(hsdata.first);
311 if (hsdata.first == 8) {
317 emsg =
"rootd: failed to start daemon: ";
321 XPDFORM(emsg,
"rootd-file serving not authorized for host '%s'", lp->Host());
324 emsg =
"rootd-file serving not enabled";
327 if (emsg.length() > 0) {
328 lp->setEtext(emsg.c_str());
330 lp->setEtext(
"link transfered");
332 return (XrdProtocol *)0;
334 TRACE(XERR,
"peeked incomplete or empty information! (dlen: "<<dlen<<
" bytes)");
335 return (XrdProtocol *)0;
339 hsdata.third = ntohl(hsdata.third);
340 if (dlen !=
sizeof(hsdata) || hsdata.first || hsdata.second
341 || !(hsdata.third == 1) || hsdata.fourth || hsdata.fifth)
return 0;
344 if (!lp->Send((
char *)&hsresp,
sizeof(hsresp))) {
345 lp->setEtext(
"Match: handshake failed");
346 TRACE(XERR,
"handshake failed");
347 return (XrdProtocol *)0;
351 int len =
sizeof(hsdata);
352 if (lp->Recv(hsbuff, len) != len) {
353 lp->setEtext(
"Match: reread failed");
354 TRACE(XERR,
"reread failed");
355 return (XrdProtocol *)0;
364 snprintf(xp->
fSecEntity.prot, XrdSecPROTOIDSIZE,
"host");
365 xp->
fSecEntity.host = strdup((
char *)lp->Host());
369 if (xp->
GetData(
"dummy",(
char *)&dum[0],
sizeof(dum)) != 0) {
371 return (XrdProtocol *)0;
375 return (XrdProtocol *)xp;
384 XPDLOC(ALL,
"Protocol::StartRootd")
394 if ((pid =
fgMgr->
Sched()->Fork(lp->Name()))) {
396 emsg =
"rootd fork failed";
409 dup2(lp->FDnum(), STDIN_FILENO);
410 dup2(lp->FDnum(), STDOUT_FILENO);
413 execv((
const char *)prog, (
char *
const *)progArg);
414 TRACE(XERR,
"rootd: Oops! Exec(" <<prog <<
") failed; errno: " <<errno);
424 emsg =
"ROOT version undefined!";
430 if (access(pexe.c_str(), X_OK) != 0) {
431 XPDFORM(emsg,
"path '%s' does not exist or is not executable (errno: %d)",
432 pexe.c_str(), (int)errno);
437 XrdOucString cmd,
exp;
438 XPDFORM(cmd,
"export ROOTBINDIR=\"%s\"; %s 20 0 %s %s", roo->
BinDir(),
441 while (progArg[n] != 0) {
442 cmd +=
" "; cmd += progArg[
n]; n++;
446 if (system(cmd.c_str()) == -1) {
447 XPDFORM(emsg,
"failure from 'system' (errno: %d)", (
int)errno);
454 if (!uconn || !uconn->isvalid(0)) {
455 XPDFORM(emsg,
"failure accepting callback (errno: %d)", -err);
456 if (uconn)
delete uconn;
459 TRACE(HDBG,
"proofexecv connected!");
463 int fd = dup(lp->FDnum());
464 if (fd < 0 || (rcc = uconn->senddesc(fd)) != 0) {
465 XPDFORM(emsg,
"failure sending descriptor '%d' (original: %d); (errno: %d)", fd, lp->FDnum(), -rcc);
466 if (uconn)
delete uconn;
483 static char statfmt[] =
"<stats id=\"xproofd\"><num>%ld</num></stats>";
487 return sizeof(statfmt)+16;
490 return snprintf(buff, blen, statfmt,
fgCount);
518 std::vector<XrdProofdResponse *>::iterator ii =
fResponses.begin();
532 XPDLOC(ALL,
"Protocol::Configure")
545 XrdProofdTrace =
new XrdOucTrace(&
fgEDest);
582 mp =
"global manager created";
587 " build "<<XrdVERSION<<
" successfully loaded");
599 XPDLOC(ALL,
"Protocol::Process")
602 TRACEP(
this, DBG,
"instance: " <<
this);
607 TRACEP(
this, HDBG,
"after GetData: rc: " << rc);
615 memcpy((
void *)&sid, (
const void *)&(
fRequest.
header.streamid[0]), 2);
619 TRACEP(
this, XERR,
"could not get Response instance for rid: "<< sid);
634 response->
Send(kXR_ArgInvalid,
"Process: Invalid request data length");
635 return fLink->setEtext(
"Process: protocol data length error");
643 response->
Send(kXR_ArgTooLong,
"fRequest.argument is too long");
661 XPDLOC(ALL,
"Protocol::Process2")
677 TRACEP(
this, XERR,
"client undefined!!! ");
678 response->Send(kXR_InvalidRequest,
"client undefined!!! ");
708 TRACE(XERR,
"link is undefined! ");
719 TRACE(XERR,
"link is undefined! ");
730 XPDLOC(ALL,
"Protocol::Recycle")
732 const char *srvtype[6] = {
"ANY",
"MasterWorker",
"MasterMaster",
733 "ClientMaster",
"Internal",
"Admin"};
756 TRACE(REQ,
"External disconnection of protocol associated with pid "<<
fPid);
760 discpath.replace(
"/cid",
"/disconnected");
761 FILE *fd = fopen(discpath.c_str(),
"w");
762 if (!fd && errno != ENOENT) {
763 TRACE(XERR,
"unable to create path: " <<discpath<<
" (errno: "<<errno<<
")");
776 TRACE(REQ,
"Non-destroyed proofserv processes attached to this protocol ("<<
this<<
777 "), setting reconnect time");
782 TRACE(XERR,
"No XrdProofdMgr ("<<
fgMgr<<
") or SessionMgr ("
824 XPDLOC(ALL,
"Protocol::GetBuff")
826 TRACE(HDBG,
"len: "<<quantum);
831 if (quantum >= argp->bsize / 2 && quantum <= argp->
bsize)
841 if ((argp =
fgBPool->Obtain(quantum)) == 0) {
842 TRACE(XERR,
"could not get requested buffer (size: "<<quantum<<
843 ") = insufficient memory");
845 TRACE(HDBG,
"quantum: "<<quantum<<
846 ", buff: "<<(
void *)(argp->buff)<<
", bsize:"<<argp->bsize);
867 XPDLOC(ALL,
"Protocol::GetData")
873 TRACEP(
this, HDBG,
"dtype: "<<(dtype ? dtype :
" - ")<<
", blen: "<<blen);
878 if (rlen != -ENOMSG && rlen != -ECONNRESET) {
879 XrdOucString emsg =
"link read error: errno: ";
881 TRACEP(
this, XERR, emsg.c_str());
882 return (
fLink ?
fLink->setEtext(emsg.c_str()) : -1);
884 TRACEP(
this, HDBG,
"connection closed by peer (errno: "<<-rlen<<
")");
889 TRACEP(
this, DBG, dtype <<
" timeout; read " <<rlen <<
" of " <<blen <<
" bytes - rescheduling");
892 TRACEP(
this, HDBG,
"rlen: "<<rlen);
903 XPDLOC(ALL,
"Protocol::SendData")
917 if (!argp)
return -1;
925 if ((rc =
GetData(
"data", argp->buff, quantum))) {
929 if (buf && !(*buf) && savebuf)
934 XPDFORM(msg,
"EXT: server ID: %d, sending: %d bytes", sid, quantum);
936 argp->buff, quantum) != 0) {
938 XPDFORM(msg,
"EXT: server ID: %d, problems sending: %d bytes to server",
948 XPDFORM(msg,
"INT: client ID: %d, sending: %d bytes", cid, quantum);
949 if (xps->
SendData(cid, argp->buff, quantum) != 0) {
951 XPDFORM(msg,
"INT: client ID: %d, problems sending: %d bytes to client",
979 XPDLOC(ALL,
"Protocol::SendDataN")
993 if (!argp)
return -1;
997 if ((rc =
GetData(
"data", argp->buff, quantum))) {
1001 if (buf && !(*buf) && savebuf)
1005 if (xps->
SendDataN(argp->buff, quantum) != 0) {
1028 XPDLOC(ALL,
"Protocol::SendMsg")
1030 static const char *crecv[5] = {
"master proofserv",
"top master",
1031 "client",
"undefined",
"any"};
1044 XPDFORM(msg,
"%s: session ID not found: %d", (
Internal() ?
"INT" :
"EXT"), psid);
1045 TRACEP(
this, XERR, msg.c_str());
1046 response->Send(kXR_InvalidRequest, msg.c_str());
1057 XPDFORM(msg,
"EXT: sending %d bytes to proofserv (psid: %d, xps: %p, status: %d,"
1058 " cid: %d)", len, psid, xps, xps->
Status(),
fCID);
1059 TRACEP(
this, HDBG, msg.c_str());
1064 TRACEP(
this, REQ,
"EXT: error getting clientSID");
1069 TRACEP(
this, REQ,
"EXT: error sending message to proofserv");
1081 XPDFORM(msg,
"INT: sending %d bytes to client/master (psid: %d, xps: %p, status: %d)",
1082 len, psid, xps, xps->
Status());
1083 TRACEP(
this, HDBG, msg.c_str());
1085 bool saveStartMsg = 0;
1089 TRACEP(
this, DBG,
"INT: setting proofserv in 'idle' state");
1094 TRACEP(
this, DBG,
"INT: got message with query number");
1096 TRACEP(
this, DBG,
"INT: setting proofserv in 'running' state");
1107 TRACEP(
this, DBG,
"INT: broadcasting log message");
1116 if (
SendData(xps, -1, &savedBuf, saveStartMsg) != 0) {
1118 "SendMsg: INT: session is reconnecting: retry later");
1123 if (
SendDataN(xps, &savedBuf, saveStartMsg) != 0) {
1125 "SendMsg: INT: session is reconnecting: retry later");
1137 XPDFORM(msg,
"INT: message sent to %s (%d bytes)", crecv[ii], len);
1153 XPDLOC(ALL,
"Protocol::Urgent")
1155 unsigned int rc = 0;
1165 TRACEP(
this, REQ,
"psid: "<<psid<<
", type: "<< type);
1170 TRACEP(
this, XERR,
"session ID not found: "<<psid);
1171 response->Send(kXR_InvalidRequest,
"Urgent: session ID not found");
1175 TRACEP(
this, DBG,
"xps: "<<xps<<
", status: "<<xps->
Status());
1178 if (!xps->
Match(psid)) {
1185 response->Send(
kXP_InvalidRequest,
"Urgent: session response object undefined - do nothing");
1190 int len = 3 *
sizeof(kXR_int32);
1191 char *buf =
new char[len];
1193 kXR_int32 itmp =
static_cast<kXR_int32
>(htonl(type));
1194 memcpy(buf, &itmp,
sizeof(kXR_int32));
1196 itmp =
static_cast<kXR_int32
>(htonl(int1));
1197 memcpy(buf +
sizeof(kXR_int32), &itmp,
sizeof(kXR_int32));
1199 itmp =
static_cast<kXR_int32
>(htonl(int2));
1200 memcpy(buf + 2 *
sizeof(kXR_int32), &itmp,
sizeof(kXR_int32));
1204 "Urgent: could not propagate request to proofsrv");
1210 TRACEP(
this, DBG,
"request propagated to proofsrv");
1221 XPDLOC(ALL,
"Protocol::Interrupt")
1230 TRACEP(
this, REQ,
"psid: "<<psid<<
", type:"<<type);
1235 TRACEP(
this, XERR,
"session ID not found: "<<psid);
1236 response->Send(kXR_InvalidRequest,
"Interrupt: session ID not found");
1243 if (!xps->
Match(psid)) {
1249 XPDFORM(msg,
"xps: %p, link ID: %s, proofsrv PID: %d",
1251 TRACEP(
this, DBG, msg.c_str());
1256 "Interrupt: could not propagate interrupt code to proofsrv");
1262 TRACEP(
this, DBG,
"interrupt propagated to proofsrv");
1277 XPDLOC(ALL,
"Protocol::Ping")
1283 TRACEP(
this, HDBG,
"INT: nothing to do ");
1293 TRACEP(
this, REQ,
"psid: "<<psid<<
", async: "<<asyncopt);
1299 TRACEP(
this, XERR,
"session ID not found: "<<psid);
1300 response->Send(kXR_InvalidRequest,
"session ID not found");
1305 kXR_int32 pingres = (psid > -1) ? 0 : 1;
1306 if (psid > -1 && xps && xps->
IsValid()) {
1308 TRACEP(
this, DBG,
"EXT: psid: "<<psid);
1314 if (asyncopt == 1) {
1315 TRACEP(
this, DBG,
"EXT: async: notifying timeout to client: "<<checkfq<<
" secs");
1316 response->Send(kXR_ok, checkfq);
1321 if (path.length() <= 0) {
1322 TRACEP(
this, XERR,
"EXT: admin path is empty! - protocol error");
1324 response->Send(
kXP_ServerError,
"EXT: admin path is empty! - protocol error");
1334 if (stat(path.c_str(), &st0) != 0) {
1335 TRACEP(
this, XERR,
"EXT: cannot stat admin path: "<<path);
1346 if ((now - st0.st_mtime) > checkfq - 5) {
1349 TRACEP(
this, XERR,
"EXT: could not send verify request to proofsrv");
1351 response->Send(
kXP_ServerError,
"EXT: could not verify reuqest to proofsrv");
1358 if (stat(path.c_str(), &st1) == 0) {
1359 if (st1.st_mtime > st0.st_mtime) {
1365 TRACEP(
this, DBG,
"EXT: waiting "<<ns<<
" secs for session "<<pid<<
1366 " to touch the admin path");
1380 TRACEP(
this, DBG,
"EXT: notified the result to client: "<<pingres);
1381 if (asyncopt == 0) {
1382 response->Send(kXR_ok, pingres);
1385 int len =
sizeof(kXR_int32);
1386 char *buf =
new char[len];
1388 kXR_int32 ifw = (kXR_int32)0;
1389 ifw =
static_cast<kXR_int32
>(htonl(ifw));
1390 memcpy(buf, &ifw,
sizeof(kXR_int32));
1391 response->Send(kXR_attn,
kXPD_ping, buf, len);
1394 }
else if (psid > -1) {
1396 TRACEP(
this, XERR,
"session ID not found: "<<psid);
1400 response->Send(kXR_ok, pingres);
1412 XPDLOC(ALL,
"Protocol::PostSession")
1416 int pid = (xps) ? xps->
SrvPID() : -1;
1418 TRACE(XERR,
"undefined session or process id");
1422 XPDFORM(buf,
"%d %s %s %d", on, u, g, pid);
1425 buf.c_str()) != 0) {
1426 TRACE(XERR,
"problem posting the prority manager pipe");
1432 TRACE(DBG,
"posting the scheduler pipe");
1434 TRACE(XERR,
"problem posting the scheduler pipe");
1441 TRACE(XERR,
"problem posting the session manager pipe");
1453 XPDLOC(ALL,
"Protocol::TouchAdminPath")
1466 apath.replace(
"/activesessions/",
"/terminatedsessions/");
1467 apath.replace(
".status",
"");
1470 if (rc != 0 && rc != -ENOENT) {
1471 const char *type =
Internal() ?
"internal" :
"external";
1472 TRACEP(
this, XERR, type<<
": problems touching "<<apath<<
"; errno: "<<-rc);
1485 XPDLOC(ALL,
"Protocol::CtrlC")
1487 TRACEP(
this, ALL,
"handling request");
static void PostSession(int on, const char *u, const char *g, XrdProofdProofServ *xps)
Post change of session status.
XrdProofdResponse * Response() const
XrdProofdProtocol * objectItem()
static XpdObjectQ fgProtStack
void SetReconnectTime(bool on=1)
Change reconnecting status.
static XrdSysLogger * fgLogger
int ResetClientSlot(int ic)
Reset slot at 'ic'.
XrdSecEntity * fSecClient
XrdProtocol * Match(XrdLink *lp)
Check whether the request matches this protocol.
int DoDirectiveClass(XrdProofdDirective *, char *val, XrdOucStream *cfg, bool rcf)
Generic class directive processor.
const char ** RootdArgs() const
struct XPClientInterruptRequest interrupt
int Config(bool rcf=0)
Run configuration and parse the entered config directives.
bool Match(short int id) const
#define TRACE(Flag, Args)
int Process(XrdProofdProtocol *p)
Process manager request.
int CheckFrequency() const
int DeleteFromSessions(const char *pid)
Delete from the hash list the session with ID pid.
const char * RootdExe() const
void setItem(XrdProofdProtocol *ival)
int SendDataN(void *buff, int len)
Send data over the open client links of this session.
static XrdSysError fgEDest
XrdProofdProofServMgr * SessionMgr() const
bool Alive(XrdProofdProtocol *p)
Check destroyed status.
static XrdSysRecMutex fgBMutex
#define kXPD_ClientMaster
virtual void RegisterDirectives()
static int ChangePerm(uid_t uid, gid_t gid)
static XrdBuffer * GetBuff(int quantum, XrdBuffer *argp=0)
Allocate a buffer to handle quantum bytes; if argp points to an existing buffer, its size is checked ...
struct ClientRequestHdr header
XrdROOT * DefaultVersion() const
const char * BinDir() const
static int Configure(char *parms, XrdProtocol_Config *pi)
Protocol configuration tool Function: Establish configuration at load time.
int BroadcastCtrlC(const char *usr)
Broadcast a ctrlc interrupt Return 0 on success, -1 on error.
static XrdBuffManager * fgBPool
static XrdProofdManager * fgMgr
std::vector< XrdProofdResponse * > fResponses
int CheckActiveSessions(bool verify=1)
Go through the active sessions admin path and make sure sessions are alive.
void Reset()
Reset static and local vars.
XrdProofdClient * fPClient
void DisconnectFromProofServ(int pid)
Change reconnecting status.
XrdSecProtocol * fAuthProt
struct XPClientSendRcvRequest sendrcv
XrdProofSched * ProofSched() const
const char * TraceID() const
virtual int DoDirective(XrdProofdDirective *, char *, XrdOucStream *, bool)
unsigned char fClntCapVer
#define TRACESET(act, on)
void Push(XpdObject *Node)
Push back a protocol.
XrdProofdResponse * Response(kXR_unt16 rid)
Get response instance corresponding to stream ID 'sid'.
static const char * ProofRequestTypes(int type)
Translates the proof request type in a human readable string.
XrdProofdProtocol * Pop()
Pop up a protocol object.
#define XrdSysMutexHelper
struct XPClientProofRequest proof
void Set(XrdLink *l)
Set the link to be used by this response.
void Recycle(XrdLink *lp, int x, const char *y)
Recycle call. Release the instance and give it back to the stack.
bool IsRootdAllowed(const char *host)
Check if 'host' is allowed to access files via rootd.
XrdScheduler * Sched() const
static int Touch(const char *path, int opt=0)
Set access (opt == 1), modify (opt =2 ) or access&modify (opt = 0, default) times of path to current ...
const char * AdminPath() const
#define TRACEP(p, act, x)
int MvSession(const char *fpid)
Move session file from the active to the terminated areas.
XrdProofdNetMgr * NetMgr() const
int GetData(const char *dtype, char *buff, int blen)
Get data from the open link.
#define XPD_SETRESPV(p, x)
int Touch(bool reset=0)
Send a touch the connected clients: this will remotely touch the associated TSocket instance and sche...
XrdProofdProtocol(XrdProtocol_Config *pi=0)
Protocol constructor.
rpdunixsrv * RootdUnixSrv() const
void TouchAdminPath()
Recording time of the last request on this instance.
int Process2()
Local processing method: here the request is dispatched to the appropriate method.
int SendData(int cid, void *buff, int len)
Send data to client cid.
XrdSysRecMutex fCtrlcMutex
XrdProofdResponse * GetNewResponse(kXR_unt16 rid)
Create new response instance for stream ID 'sid'.
int Ping()
Handle a ping request.
#define kXPD_startprocess
static int fgEUidAtStartup
int Process(XrdLink *lp)
Process the information received on the active link.
#define XPD_SETRESP(p, x)
R__EXTERN C unsigned int sleep(unsigned int seconds)
static XrdSysLogger gMainLogger
int StartRootd(XrdLink *lp, XrdOucString &emsg)
Transfer the connection to a rootd daemon to serve a file access request Return 0 on success...
XrdProofdPriorityMgr * PriorityMgr() const
int Urgent()
Handle generic request of a urgent message to be forwarded to the server.
int XrdgetProtocolPort(const char *, char *, XrdProtocol_Config *pi)
This function is called early on to determine the port we need to use.
XrdProtocol * XrdgetProtocol(const char *, char *parms, XrdProtocol_Config *pi)
This protocol is meant to live in a shared library.
static void ReleaseBuff(XrdBuffer *argp)
Release a buffer previously allocated via GetBuff.
int Stats(char *buff, int blen, int do_sync)
Return statistics info about the protocol.
struct ResetCtrlcGuard ResetCtrlcGuard_t
const char * User() const
XrdROOTMgr * ROOTMgr() const
int Interrupt()
Handle an interrupt request.
int SendDataN(XrdProofdProofServ *xps, XrdSrvBuffer **buf=0, bool sb=0)
Send data over the open client links of session 'xps'.
int Post(int type, const char *msg)
Post message on the pipe.
void Set(int inQMax, time_t agemax=1800)
Lock the data area and set the values.
int SendMsg()
Handle a request to forward a message to another process.
static int VerifyProcessByID(int pid, const char *pname="proofserv")
Check if a process named 'pname' and process 'pid' is still in the process table. ...
XrdOucTrace * XrdProofdTrace
XrdProofdProofServ * GetServer(int psid)
Get from the vector server instance with ID psid.
int CtrlC()
Set and propagate a Ctrl-C request.
int VerifyProofServ(bool fw)
Check if the associated proofserv process is alive.
int Send(void)
Auxilliary Send method.
void SetStartMsg(XrdSrvBuffer *sm)
int SendData(XrdProofdProofServ *xps, kXR_int32 sid=-1, XrdSrvBuffer **buf=0, bool sb=0)
Send data over the open link. Segmentation is done here, if required.
XrdProofdClient * Client() const