ROOT logo
// $Id: XrdEhs.cxx 2774 2012-06-12 22:48:33Z matevz $

// Copyright (C) 1999-2008, Matevz Tadel. All rights reserved.
// This file is part of GLED, released under GNU General Public License version 2.
// For the licensing terms see $GLEDSYS/LICENSE or http://www.gnu.org/.

#include "XrdEhs.h"
#include "XrdMonSucker.h"
#include "XrdEhs.c7"

#include "XrdFile.h"
#include "XrdUser.h"
#include "XrdServer.h"

#include "Glasses/ZHashList.h"
#include "Gled/GThread.h"
#include "Stones/SServerSocket.h"

#include "TSystem.h"

#include <iostream>
#include <sstream>
#include <string>

#include <cstdlib>

// XrdEhs

//______________________________________________________________________________
// Status reporting embedded http server.
//
// This used EHS once and supported ?mode=all|files|help but it locked itself
// up regularly and so it got dumped.
//
// TODO:
// - Needs proper thread cancellation.
// - Read the request. (Only 'GET' line is read and parsed for path, args.)
// - Would be nice to return proper header, beyond 200 OK.
//   (Somewhat done, but pointless without full request parsing, I reckon.)

ClassImp(XrdEhs);

//==============================================================================

void XrdEhs::_init()
{}

XrdEhs::XrdEhs(const Text_t* n, const Text_t* t) :
   ZNameMap(n, t),
   m_req_line_re("^GET\\s+/?(.*)\\s+HTTP/([\\d\\.]+)$", "o"),
   m_req_re("^([^?]*)(?:\\?(.*))?$", "o"),
   mPort(4242),
   bServerUp(false),
   bParanoia(false)
{
  _init();
}

XrdEhs::~XrdEhs()
{}

//==============================================================================

void XrdEhs::fill_content(const GTime& req_time, TString& content, lStr_t& path, mStr2Str_t& args)
{
  GMutexHolder _lck(mServeMutex);

  if ((req_time - mServeTime) > GTime(1, 0))
  {
    ZHashList* hl = mXrdSucker->GetOpenFiles();
    if (mFileListTS != hl->GetTimeStamp())
    {
      mFileList.clear();
      mFileListTS = hl->CopyListByGlass<XrdFile>(mFileList);
    }

    bool fqhn         = (args["fqhn"] == "1");
    bool no_same_site = (args["no_same_site"] == "1");

    int  file_len = 64;
    if ( ! args["file_len"].IsNull()) file_len = TMath::Max(0, args["file_len"].Atoi());

    TPMERegexp short_domain("[^\\.]+\\.[^\\.]+$", "o");

    TPMERegexp srv_re, cli_re, usr_re, fil_re;

    bool f_srv = ( ! args["server_re"].IsNull());
    if (f_srv) srv_re.Reset(args["server_re"], "o");

    bool f_cli = ( ! args["client_re"].IsNull());
    if (f_cli) cli_re.Reset(args["client_re"], "o");

    bool f_usr = ( ! args["user_re"].IsNull());
    if (f_usr) usr_re.Reset(args["user_re"], "o");

    bool f_fil = ( ! args["file_re"].IsNull());
    if (f_fil) fil_re.Reset(args["file_re"], "o");

    bool any_fil  = no_same_site || f_srv || f_cli || f_usr || f_fil;
    int  pass_cnt = 0;

    ostringstream oss;

    TPMERegexp rePath("/");
    bool odd = false;
    for (list<XrdFile*>::iterator xfi = mFileList.begin(); xfi != mFileList.end(); ++xfi)
    {
      odd = !odd;
      XrdFile *file = *xfi;
      XrdUser *user = file->GetUser();

      TString server_id = fqhn ? user->GetServer()->GetFqhn() : user->GetServer()->RefDomain();
      TString client_id = fqhn ? user->GetFromFqhn()          : user->RefFromDomain();

      if (no_same_site)
      {
        short_domain.Match(user->GetServer()->RefDomain());
        TString srv = short_domain[0];
        short_domain.Match(user->RefFromDomain());
        TString clt = short_domain[0];
        if (srv == clt)
          continue;
      }
      if (f_srv && ! srv_re.Match(server_id))           continue;
      if (f_cli && ! cli_re.Match(client_id))           continue;
      if (f_usr && ! usr_re.Match(user->RefRealName())) continue;
      if (f_fil && ! fil_re.Match(file->RefName()))     continue;

      ++pass_cnt;

      oss << Form("<tr class='row%d'>", odd ? 1 : 2)<< endl; 

      if (! bParanoia)
      {
        TString fn(file->RefName());
        if (file_len && fn.Length() > file_len) {
          fn.Resize(file_len);
          fn += "...";
        }
        oss << "<td>" << fn << "</td>" << endl;
      }
      else
      {
        if (file->RefName().BeginsWith("/store/user/"))
          oss << "<td>/store/user</td>" << endl;
        else if (rePath.Split(file->RefName()) > 3)
          oss << Form("<td>/%s/%s/%s</td>", rePath[1].Data(), rePath[2].Data(), rePath[3].Data()) <<endl;
        else
          oss << Form("<td>%s</td>", file->GetName()) << endl;
      }

      if (bParanoia && ! user->RefRealName().IsNull())
      {
        oss << "<td>" << Form("%X",  user->RefRealName().Hash()) <<  "</td>" << endl;
      }
      else
      {
        oss << "<td>" << user->GetRealName() << "</td>" << endl;
      }
      oss << "<td>" << server_id << "</td>" << endl;
      oss << "<td>" << client_id << "</td>" << endl;

      GTime    open_t = req_time - file->RefOpenTime();
      GTime    lmsg_t = req_time - file->RefLastMsgTime();
      Double_t sum_mb = file->GetReadStats().GetSumX();
      Double_t siz_mb = file->GetSizeMB();

      oss << "<td>" << open_t.ToHourMinSec(true) << "</td>" << endl;
      oss << "<td>" << lmsg_t.ToHourMinSec(true) << "</td>" << endl;

      oss << "<td>" << GForm("%.3f", sum_mb) << "</td>" << endl;
      oss << "<td>" << GForm("%.3f", siz_mb ? 100.0*sum_mb/siz_mb : 0.0) << "</td>" << endl;
      oss << "<td>" << GForm("%.3f", sum_mb / open_t.ToDouble()) << "</td>" << endl;
      oss << "<td>" << GForm("%.3f", file->GetReadStats().GetAverage()) << "</td>" << endl;

      oss << "</tr>" << endl;
    }
    oss << "</table>" << endl;
    oss << "</body>"  << endl;
    oss << "</html>"  << endl;


    // Generate table header

    ostringstream osh;
    osh << "<html>" << std::endl;
    osh << "<meta http-equiv=\"refresh\" content=\"180\" />" << endl;
    osh << "<head> <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"> " << std::endl;
    osh << "<style type=\"text/css\">" << std::endl << std::endl;
     
    osh << "table.demo {" << std::endl;
    osh << "   background-color: #C0C0FF;" << std::endl;
    osh << "   padding: 2px 5px 2px 5px;" << std::endl;
    osh << "}" << std::endl;
    osh << "tr.row1 {" << std::endl;
    osh << "   background-color: #FFFFFF;" << std::endl;
    osh << "}" << std::endl;
    osh << "tr.row2 {" << std::endl;
    osh << "   background-color: #E0E0FF;" << std::endl;
    osh << "}" << std::endl;
    osh << "</style> "<< std::endl;
    osh << "<title>Xrd open files [";
    if (any_fil) osh << pass_cnt << "/";
    osh << mFileList.size() << "]</title> " << std::endl;
    osh << "</head>" << std::endl;
    
    osh << "<script type=\"text/javascript\" src=\"http://uaf-2.t2.ucsd.edu/~alja/gs_sortable.js\"></script>" << std::endl;
    osh << "<script type=\"text/javascript\">" << std::endl;
    osh << "" << std::endl;
   
    osh << "TSort_Data = new Array ('table_xrd_cms_openfiles', 's',  's', 's', 's', 's', 's', 'f', 'f', 'f', 'f');" << std::endl;
    osh << "TSort_Classes = new Array ('row2', 'row1');" << std::endl;
    osh << "TSort_Initial = new Array ('0D');" << std::endl;
    osh << "var TSort_Icons = new Array (' V', ' &#923;');" << std::endl;
    osh << "var TSort_Cookie = 'table_xrd_cms_openfiles';" << std::endl;
    osh << "tsRegister();" << std::endl;
    osh << "</script>" << std::endl;


    osh << "<TABLE id=\"table_xrd_cms_openfiles\" class=\"demo\" width=100%>" << std::endl;
    osh << "<thead>"  << std::endl;

    // header
    osh << "<tr>"<< endl;
    osh << "<th align=\"left\">File</th>";
    osh << "<th align=\"left\">User" << (bParanoia ? " Hash" : "") << "</th>";
    osh << "<th align=\"left\">Server" << (fqhn ? "" : " Domain") << "</th>";
    osh << "<th align=\"left\">Client" << (fqhn ? "" : " Domain") << "</th>";
    osh << "<th align=\"left\">Open Ago</th>";
    osh << "<th align=\"left\">Update Ago</th>";
    osh << "<th align=\"left\">Read [MB]</th>";
    osh << "<th align=\"left\">Read [%]</th>";
    osh << "<th align=\"left\">Rate [MB/s]</th>";
    osh << "<th align=\"left\">Avg Read [MB]</th>";
    osh << endl;
    osh << "</tr>" << endl;

    osh << "</thead>" << std::endl;

    content  = osh.str();
    content += oss.str();
  }
}

//==============================================================================

namespace
{
  struct serve_page_arg
  {
    XrdEhs  *xehs;
    SSocket *sock;
    serve_page_arg(XrdEhs* e, SSocket *s) : xehs(e), sock(s) {}
  };

  void* serve_page_tl(serve_page_arg* arg)
  {
    try
    {
      arg->xehs->ServePage(arg->sock);
    }
    catch (Exc_t& e)
    {
      arg->sock->SendRaw(e.Data(), e.Length());
    }
    arg->sock->Close();
    delete arg->sock;
    delete arg;
    return 0;
  }
}

void XrdEhs::ServePage(SSocket* sock)
{
  static const Exc_t _eh("XrdEhs::ServePage ");

  GTime now = GTime::ApproximateTime();

  const Int_t buf_size = 4096;
  char        buf[buf_size];

  {
    Int_t len = 0;
    while (1)
    {
      Int_t ret = sock->RecvRaw(&buf[len], 1);
      if (ret < 0) {
        throw _eh + GForm("Error sucking %d.", ret);
      }
      if (buf[len] == 10 || buf[len] == 13) {
        buf[len] = 0;
        break;
      }
      if (++len >= buf_size)
        throw _eh + "Request longer than 4k, eat it yourself.";
    }
  }
  TString req_line(buf);
  req_line.ReplaceAll("%20", " ");
  TString path, args;
  {
    GMutexHolder _re_lck(m_re_mutex);
    if (m_req_line_re.Match(req_line) != 3)
      throw _eh + "Strange request line: '" + req_line + "'.";
    Int_t n_req = m_req_re.Match(m_req_line_re[1]);
    if (n_req != 2 && n_req != 3)
      throw _eh + "Strange URL: '" + m_req_line_re[1] + "'.";
    path = m_req_re[1];
    args = m_req_re[2];
  }

  TString xxx = "<p><hr><p>";

  lStr_t path_list;
  if (! path.IsNull())
  {
    TPMERegexp sp("/+");
    Int_t np = sp.Split(path);
    xxx += "Request path: '" + path + "'<p>";
    for (Int_t n = 0; n < np; ++n)
    {
      xxx += GForm("%2d '%s'<p>", n + 1, sp[n].Data());
      path_list.push_back(sp[n]);
    }

    xxx += "<p>";
  }

  mStr2Str_t args_map;
  if (! args.IsNull())
  {
    xxx += "Request args: '" + args + "'<p>";
    TPMERegexp sa("&+");
    Int_t na = sa.Split(args);
    TPMERegexp sv("=");
    for (Int_t n = 0; n < na; ++n)
    {
      Int_t nsa = sv.Split(sa[n]);
      if (nsa < 1 || nsa > 2)
        throw _eh + "URL parameter error: '" + sa[n] + "'.";
      if (nsa == 2) {
	xxx += GForm("%2d. '%s' = '%s'<p>", n + 1, sv[0].Data(), sv[1].Data());
	args_map[sv[0]] = sv[1];
      } else {
	xxx += GForm("%2d. '%s' = '1'<p>", n + 1, sv[0].Data());
	args_map[sv[0]] = "1";
      }
    }
  }

  TString content;
  fill_content(now, content, path_list, args_map);

  content += xxx;

  // sock->SetOption(kNoBlock, 1);
  // Int_t len = sock->RecvRaw(request, 8192);


  ostringstream hdr;

  hdr << "HTTP/1.1 200 OK" << "\r\n";
  hdr << "Date: " << now.ToWebTimeGMT() << "\r\n";
  hdr << "Connection: close" << "\r\n";
  hdr << "Content-Type: text/html" << "\r\n";
  hdr << "Content-Length: " << content.Length() << "\r\n";
  hdr << "\r\n";

  sock->SendRaw(hdr.str().c_str(), hdr.str().length());
  sock->SendRaw(content.Data(), content.Length());

  GTime::SleepMiliSec(1000);
}

//==============================================================================

void XrdEhs::StartServer()
{
  static const Exc_t _eh("XrdEhs::StartServer ");

  assert_xrdsucker(_eh);

  {
    GMutexHolder _lck(mServeMutex);

    if (bServerUp)
      throw _eh + "server already running.";

    mServeTime.SetZero();
    mFileListTS = 0;

    bServerUp = true;
    b_stop_server = false;
  }

  SServerSocket serv_sock(mPort, true);
  if (! serv_sock.IsValid())
  {
    throw _eh + "Creation of server socket failed.";
  }

  GSelector     selector;
  selector.fRead.Add(&serv_sock);

  while (! b_stop_server)
  {
    selector.Select();
    SSocket *sock = serv_sock.Accept();

    if (sock == 0)
    {
      ISerr(_eh + "Accept failed, retrying ...");
      continue;
    }

    GThread *thr = new GThread("XrdEhs-PageSender", (GThread_foo) serve_page_tl, new serve_page_arg(this, sock), true);
    thr->SetNice(20);
    thr->Spawn();
  }

  {
    GMutexHolder _lck(mServeMutex);
    bServerUp = false;
  }
}

void XrdEhs::StopServer()
{
  static const Exc_t _eh("XrdEhs::StopServer ");

  {
    GMutexHolder _lck(mServeMutex);

    if ( ! bServerUp)
      throw _eh + "server not running.";

    b_stop_server = true;
    // should know thread and kill it
  }
}
 XrdEhs.cxx:1
 XrdEhs.cxx:2
 XrdEhs.cxx:3
 XrdEhs.cxx:4
 XrdEhs.cxx:5
 XrdEhs.cxx:6
 XrdEhs.cxx:7
 XrdEhs.cxx:8
 XrdEhs.cxx:9
 XrdEhs.cxx:10
 XrdEhs.cxx:11
 XrdEhs.cxx:12
 XrdEhs.cxx:13
 XrdEhs.cxx:14
 XrdEhs.cxx:15
 XrdEhs.cxx:16
 XrdEhs.cxx:17
 XrdEhs.cxx:18
 XrdEhs.cxx:19
 XrdEhs.cxx:20
 XrdEhs.cxx:21
 XrdEhs.cxx:22
 XrdEhs.cxx:23
 XrdEhs.cxx:24
 XrdEhs.cxx:25
 XrdEhs.cxx:26
 XrdEhs.cxx:27
 XrdEhs.cxx:28
 XrdEhs.cxx:29
 XrdEhs.cxx:30
 XrdEhs.cxx:31
 XrdEhs.cxx:32
 XrdEhs.cxx:33
 XrdEhs.cxx:34
 XrdEhs.cxx:35
 XrdEhs.cxx:36
 XrdEhs.cxx:37
 XrdEhs.cxx:38
 XrdEhs.cxx:39
 XrdEhs.cxx:40
 XrdEhs.cxx:41
 XrdEhs.cxx:42
 XrdEhs.cxx:43
 XrdEhs.cxx:44
 XrdEhs.cxx:45
 XrdEhs.cxx:46
 XrdEhs.cxx:47
 XrdEhs.cxx:48
 XrdEhs.cxx:49
 XrdEhs.cxx:50
 XrdEhs.cxx:51
 XrdEhs.cxx:52
 XrdEhs.cxx:53
 XrdEhs.cxx:54
 XrdEhs.cxx:55
 XrdEhs.cxx:56
 XrdEhs.cxx:57
 XrdEhs.cxx:58
 XrdEhs.cxx:59
 XrdEhs.cxx:60
 XrdEhs.cxx:61
 XrdEhs.cxx:62
 XrdEhs.cxx:63
 XrdEhs.cxx:64
 XrdEhs.cxx:65
 XrdEhs.cxx:66
 XrdEhs.cxx:67
 XrdEhs.cxx:68
 XrdEhs.cxx:69
 XrdEhs.cxx:70
 XrdEhs.cxx:71
 XrdEhs.cxx:72
 XrdEhs.cxx:73
 XrdEhs.cxx:74
 XrdEhs.cxx:75
 XrdEhs.cxx:76
 XrdEhs.cxx:77
 XrdEhs.cxx:78
 XrdEhs.cxx:79
 XrdEhs.cxx:80
 XrdEhs.cxx:81
 XrdEhs.cxx:82
 XrdEhs.cxx:83
 XrdEhs.cxx:84
 XrdEhs.cxx:85
 XrdEhs.cxx:86
 XrdEhs.cxx:87
 XrdEhs.cxx:88
 XrdEhs.cxx:89
 XrdEhs.cxx:90
 XrdEhs.cxx:91
 XrdEhs.cxx:92
 XrdEhs.cxx:93
 XrdEhs.cxx:94
 XrdEhs.cxx:95
 XrdEhs.cxx:96
 XrdEhs.cxx:97
 XrdEhs.cxx:98
 XrdEhs.cxx:99
 XrdEhs.cxx:100
 XrdEhs.cxx:101
 XrdEhs.cxx:102
 XrdEhs.cxx:103
 XrdEhs.cxx:104
 XrdEhs.cxx:105
 XrdEhs.cxx:106
 XrdEhs.cxx:107
 XrdEhs.cxx:108
 XrdEhs.cxx:109
 XrdEhs.cxx:110
 XrdEhs.cxx:111
 XrdEhs.cxx:112
 XrdEhs.cxx:113
 XrdEhs.cxx:114
 XrdEhs.cxx:115
 XrdEhs.cxx:116
 XrdEhs.cxx:117
 XrdEhs.cxx:118
 XrdEhs.cxx:119
 XrdEhs.cxx:120
 XrdEhs.cxx:121
 XrdEhs.cxx:122
 XrdEhs.cxx:123
 XrdEhs.cxx:124
 XrdEhs.cxx:125
 XrdEhs.cxx:126
 XrdEhs.cxx:127
 XrdEhs.cxx:128
 XrdEhs.cxx:129
 XrdEhs.cxx:130
 XrdEhs.cxx:131
 XrdEhs.cxx:132
 XrdEhs.cxx:133
 XrdEhs.cxx:134
 XrdEhs.cxx:135
 XrdEhs.cxx:136
 XrdEhs.cxx:137
 XrdEhs.cxx:138
 XrdEhs.cxx:139
 XrdEhs.cxx:140
 XrdEhs.cxx:141
 XrdEhs.cxx:142
 XrdEhs.cxx:143
 XrdEhs.cxx:144
 XrdEhs.cxx:145
 XrdEhs.cxx:146
 XrdEhs.cxx:147
 XrdEhs.cxx:148
 XrdEhs.cxx:149
 XrdEhs.cxx:150
 XrdEhs.cxx:151
 XrdEhs.cxx:152
 XrdEhs.cxx:153
 XrdEhs.cxx:154
 XrdEhs.cxx:155
 XrdEhs.cxx:156
 XrdEhs.cxx:157
 XrdEhs.cxx:158
 XrdEhs.cxx:159
 XrdEhs.cxx:160
 XrdEhs.cxx:161
 XrdEhs.cxx:162
 XrdEhs.cxx:163
 XrdEhs.cxx:164
 XrdEhs.cxx:165
 XrdEhs.cxx:166
 XrdEhs.cxx:167
 XrdEhs.cxx:168
 XrdEhs.cxx:169
 XrdEhs.cxx:170
 XrdEhs.cxx:171
 XrdEhs.cxx:172
 XrdEhs.cxx:173
 XrdEhs.cxx:174
 XrdEhs.cxx:175
 XrdEhs.cxx:176
 XrdEhs.cxx:177
 XrdEhs.cxx:178
 XrdEhs.cxx:179
 XrdEhs.cxx:180
 XrdEhs.cxx:181
 XrdEhs.cxx:182
 XrdEhs.cxx:183
 XrdEhs.cxx:184
 XrdEhs.cxx:185
 XrdEhs.cxx:186
 XrdEhs.cxx:187
 XrdEhs.cxx:188
 XrdEhs.cxx:189
 XrdEhs.cxx:190
 XrdEhs.cxx:191
 XrdEhs.cxx:192
 XrdEhs.cxx:193
 XrdEhs.cxx:194
 XrdEhs.cxx:195
 XrdEhs.cxx:196
 XrdEhs.cxx:197
 XrdEhs.cxx:198
 XrdEhs.cxx:199
 XrdEhs.cxx:200
 XrdEhs.cxx:201
 XrdEhs.cxx:202
 XrdEhs.cxx:203
 XrdEhs.cxx:204
 XrdEhs.cxx:205
 XrdEhs.cxx:206
 XrdEhs.cxx:207
 XrdEhs.cxx:208
 XrdEhs.cxx:209
 XrdEhs.cxx:210
 XrdEhs.cxx:211
 XrdEhs.cxx:212
 XrdEhs.cxx:213
 XrdEhs.cxx:214
 XrdEhs.cxx:215
 XrdEhs.cxx:216
 XrdEhs.cxx:217
 XrdEhs.cxx:218
 XrdEhs.cxx:219
 XrdEhs.cxx:220
 XrdEhs.cxx:221
 XrdEhs.cxx:222
 XrdEhs.cxx:223
 XrdEhs.cxx:224
 XrdEhs.cxx:225
 XrdEhs.cxx:226
 XrdEhs.cxx:227
 XrdEhs.cxx:228
 XrdEhs.cxx:229
 XrdEhs.cxx:230
 XrdEhs.cxx:231
 XrdEhs.cxx:232
 XrdEhs.cxx:233
 XrdEhs.cxx:234
 XrdEhs.cxx:235
 XrdEhs.cxx:236
 XrdEhs.cxx:237
 XrdEhs.cxx:238
 XrdEhs.cxx:239
 XrdEhs.cxx:240
 XrdEhs.cxx:241
 XrdEhs.cxx:242
 XrdEhs.cxx:243
 XrdEhs.cxx:244
 XrdEhs.cxx:245
 XrdEhs.cxx:246
 XrdEhs.cxx:247
 XrdEhs.cxx:248
 XrdEhs.cxx:249
 XrdEhs.cxx:250
 XrdEhs.cxx:251
 XrdEhs.cxx:252
 XrdEhs.cxx:253
 XrdEhs.cxx:254
 XrdEhs.cxx:255
 XrdEhs.cxx:256
 XrdEhs.cxx:257
 XrdEhs.cxx:258
 XrdEhs.cxx:259
 XrdEhs.cxx:260
 XrdEhs.cxx:261
 XrdEhs.cxx:262
 XrdEhs.cxx:263
 XrdEhs.cxx:264
 XrdEhs.cxx:265
 XrdEhs.cxx:266
 XrdEhs.cxx:267
 XrdEhs.cxx:268
 XrdEhs.cxx:269
 XrdEhs.cxx:270
 XrdEhs.cxx:271
 XrdEhs.cxx:272
 XrdEhs.cxx:273
 XrdEhs.cxx:274
 XrdEhs.cxx:275
 XrdEhs.cxx:276
 XrdEhs.cxx:277
 XrdEhs.cxx:278
 XrdEhs.cxx:279
 XrdEhs.cxx:280
 XrdEhs.cxx:281
 XrdEhs.cxx:282
 XrdEhs.cxx:283
 XrdEhs.cxx:284
 XrdEhs.cxx:285
 XrdEhs.cxx:286
 XrdEhs.cxx:287
 XrdEhs.cxx:288
 XrdEhs.cxx:289
 XrdEhs.cxx:290
 XrdEhs.cxx:291
 XrdEhs.cxx:292
 XrdEhs.cxx:293
 XrdEhs.cxx:294
 XrdEhs.cxx:295
 XrdEhs.cxx:296
 XrdEhs.cxx:297
 XrdEhs.cxx:298
 XrdEhs.cxx:299
 XrdEhs.cxx:300
 XrdEhs.cxx:301
 XrdEhs.cxx:302
 XrdEhs.cxx:303
 XrdEhs.cxx:304
 XrdEhs.cxx:305
 XrdEhs.cxx:306
 XrdEhs.cxx:307
 XrdEhs.cxx:308
 XrdEhs.cxx:309
 XrdEhs.cxx:310
 XrdEhs.cxx:311
 XrdEhs.cxx:312
 XrdEhs.cxx:313
 XrdEhs.cxx:314
 XrdEhs.cxx:315
 XrdEhs.cxx:316
 XrdEhs.cxx:317
 XrdEhs.cxx:318
 XrdEhs.cxx:319
 XrdEhs.cxx:320
 XrdEhs.cxx:321
 XrdEhs.cxx:322
 XrdEhs.cxx:323
 XrdEhs.cxx:324
 XrdEhs.cxx:325
 XrdEhs.cxx:326
 XrdEhs.cxx:327
 XrdEhs.cxx:328
 XrdEhs.cxx:329
 XrdEhs.cxx:330
 XrdEhs.cxx:331
 XrdEhs.cxx:332
 XrdEhs.cxx:333
 XrdEhs.cxx:334
 XrdEhs.cxx:335
 XrdEhs.cxx:336
 XrdEhs.cxx:337
 XrdEhs.cxx:338
 XrdEhs.cxx:339
 XrdEhs.cxx:340
 XrdEhs.cxx:341
 XrdEhs.cxx:342
 XrdEhs.cxx:343
 XrdEhs.cxx:344
 XrdEhs.cxx:345
 XrdEhs.cxx:346
 XrdEhs.cxx:347
 XrdEhs.cxx:348
 XrdEhs.cxx:349
 XrdEhs.cxx:350
 XrdEhs.cxx:351
 XrdEhs.cxx:352
 XrdEhs.cxx:353
 XrdEhs.cxx:354
 XrdEhs.cxx:355
 XrdEhs.cxx:356
 XrdEhs.cxx:357
 XrdEhs.cxx:358
 XrdEhs.cxx:359
 XrdEhs.cxx:360
 XrdEhs.cxx:361
 XrdEhs.cxx:362
 XrdEhs.cxx:363
 XrdEhs.cxx:364
 XrdEhs.cxx:365
 XrdEhs.cxx:366
 XrdEhs.cxx:367
 XrdEhs.cxx:368
 XrdEhs.cxx:369
 XrdEhs.cxx:370
 XrdEhs.cxx:371
 XrdEhs.cxx:372
 XrdEhs.cxx:373
 XrdEhs.cxx:374
 XrdEhs.cxx:375
 XrdEhs.cxx:376
 XrdEhs.cxx:377
 XrdEhs.cxx:378
 XrdEhs.cxx:379
 XrdEhs.cxx:380
 XrdEhs.cxx:381
 XrdEhs.cxx:382
 XrdEhs.cxx:383
 XrdEhs.cxx:384
 XrdEhs.cxx:385
 XrdEhs.cxx:386
 XrdEhs.cxx:387
 XrdEhs.cxx:388
 XrdEhs.cxx:389
 XrdEhs.cxx:390
 XrdEhs.cxx:391
 XrdEhs.cxx:392
 XrdEhs.cxx:393
 XrdEhs.cxx:394
 XrdEhs.cxx:395
 XrdEhs.cxx:396
 XrdEhs.cxx:397
 XrdEhs.cxx:398
 XrdEhs.cxx:399
 XrdEhs.cxx:400
 XrdEhs.cxx:401
 XrdEhs.cxx:402
 XrdEhs.cxx:403
 XrdEhs.cxx:404
 XrdEhs.cxx:405
 XrdEhs.cxx:406
 XrdEhs.cxx:407
 XrdEhs.cxx:408
 XrdEhs.cxx:409
 XrdEhs.cxx:410
 XrdEhs.cxx:411
 XrdEhs.cxx:412
 XrdEhs.cxx:413
 XrdEhs.cxx:414
 XrdEhs.cxx:415
 XrdEhs.cxx:416
 XrdEhs.cxx:417
 XrdEhs.cxx:418
 XrdEhs.cxx:419
 XrdEhs.cxx:420
 XrdEhs.cxx:421
 XrdEhs.cxx:422
 XrdEhs.cxx:423
 XrdEhs.cxx:424
 XrdEhs.cxx:425
 XrdEhs.cxx:426
 XrdEhs.cxx:427
 XrdEhs.cxx:428
 XrdEhs.cxx:429
 XrdEhs.cxx:430
 XrdEhs.cxx:431
 XrdEhs.cxx:432
 XrdEhs.cxx:433
 XrdEhs.cxx:434
 XrdEhs.cxx:435
 XrdEhs.cxx:436
 XrdEhs.cxx:437
 XrdEhs.cxx:438
 XrdEhs.cxx:439
 XrdEhs.cxx:440