Commit 7d1450bd authored by Daniele Kruse's avatar Daniele Kruse
Browse files

First draft of server-side tpconfig handler

parent 3ff6a95a
/******************************************************************************
* castor/tape/legacymsg/AdminMarshal.cpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
*
* @author dkruse@cern.ch
*****************************************************************************/
#include "castor/exception/Internal.hpp"
#include "castor/io/io.hpp"
#include "castor/tape/legacymsg/CommonMarshal.hpp"
#include "castor/tape/legacymsg/AdminMarshal.hpp"
#include "castor/tape/utils/utils.hpp"
#include "h/rtcp_constants.h"
#include "h/vdqm_constants.h"
#include <errno.h>
#include <string.h>
//-----------------------------------------------------------------------------
// unmarshal
//-----------------------------------------------------------------------------
void castor::tape::legacymsg::unmarshal(const char * &src, size_t &srcLen, TapeMsgBody &dst) throw(castor::exception::Exception) {
io::unmarshalUint32(src, srcLen, dst.uid);
io::unmarshalUint32(src, srcLen, dst.gid);
io::unmarshalString(src, srcLen, dst.drive);
io::unmarshalInt16(src, srcLen, dst.status);
}
\ No newline at end of file
/******************************************************************************
* castor/tape/legacymsg/AdminMarshall.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
*
* @author dkruse@cern.ch
*****************************************************************************/
#ifndef CASTOR_TAPE_LEGACYMSG_ADMINMARSHAL_HPP
#define CASTOR_TAPE_LEGACYMSG_ADMINMARSHAL_HPP 1
#include "castor/exception/Exception.hpp"
#include "castor/tape/legacymsg/TapeMsgBody.hpp"
#include <errno.h>
#include <stdint.h>
#include <string>
namespace castor {
namespace tape {
namespace legacymsg {
/**
* Unmarshals a message body with the specified destination structure type
* from the specified source buffer.
*
* @param src In/out parameter, before invocation points to the source
* buffer where the message body should be unmarshalled from and on return
* points to the byte in the source buffer immediately after the
* unmarshalled message body.
* @param srcLen In/our parameter, before invocation is the length of the
* source buffer from where the message body should be unmarshalled and on
* return is the number of bytes remaining in the source buffer.
* @param dst The destination message body structure.
*/
void unmarshal(const char * &src, size_t &srcLen, TapeMsgBody &dst) throw(castor::exception::Exception);
} // namespace legacymsg
} // namespace tape
} // namespace castor
#endif // CASTOR_TAPE_LEGACYMSG_ADMINMARSHAL_HPP
......@@ -26,6 +26,7 @@ cmake_minimum_required (VERSION 2.6)
# Rules to build and install libcastortapelegacymsg.so
################################################################################
set (TAPE_LEGACYMSG_LIB_SRC_FILES
AdminMarshal.cpp
CommonMarshal.cpp
GiveOutpMsgBody.cpp
MessageHeader.cpp
......@@ -38,6 +39,7 @@ set (TAPE_LEGACYMSG_LIB_SRC_FILES
RtcpSegmentAttributes.cpp
RtcpTapeRqstMsgBody.cpp
TapeBridgeMarshal.cpp
TapeMsgBody.cpp
VdqmDrvRqstMsgBody.cpp
VdqmMarshal.cpp
VmgrMarshal.cpp
......
/******************************************************************************
* castor/tape/legacymsg/TapeMsgBody.cpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author dkruse@cern.ch
*****************************************************************************/
#include "castor/tape/legacymsg/TapeMsgBody.hpp"
#include <string.h>
castor::tape::legacymsg::TapeMsgBody::TapeMsgBody() throw():
uid(0),
gid(0),
status(0) {
memset(drive, '\0', sizeof(drive));
}
/******************************************************************************
* castor/tape/legacymsg/TapeMsgBody.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author dkruse@cern.ch
*****************************************************************************/
#ifndef CASTOR_TAPE_LEGACYMSG_TAPEMSGBODY_HPP
#define CASTOR_TAPE_LEGACYMSG_TAPEMSGBODY_HPP 1
#include "castor/tape/legacymsg/RtcpErrorAppendix.hpp"
#include "h/Castor_limits.h"
#include "h/Cuuid.h"
#include <stdint.h>
namespace castor {
namespace tape {
namespace legacymsg {
/**
* An admin command message.
*/
struct TapeMsgBody {
uid_t uid;
gid_t gid;
char drive[CA_MAXUNMLEN+1];
int16_t status;
/**
* Constructor.
*/
TapeMsgBody() throw();
}; // struct RtcpTapeRqstMsgBody
} // namespace legacymsg
} // namespace tape
} // namespace castor
#endif // CASTOR_TAPE_LEGACYMSG_TAPEMSGBODY
/******************************************************************************
* castor/tape/tapeserver/daemon/AdminAcceptHandler.cpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author dkruse@cern.ch
*****************************************************************************/
#include "castor/exception/BadAlloc.hpp"
#include "castor/exception/Errnum.hpp"
#include "castor/exception/Internal.hpp"
#include "castor/io/io.hpp"
#include "castor/tape/tapeserver/daemon/AdminAcceptHandler.hpp"
#include "castor/tape/tapeserver/daemon/VdqmConnectionHandler.hpp"
#include "castor/utils/SmartFd.hpp"
#include "h/common.h"
#include "h/serrno.h"
#include "h/Ctape.h"
#include "castor/tape/legacymsg/CommonMarshal.hpp"
#include "castor/tape/legacymsg/AdminMarshal.hpp"
#include <vdqm_api.h>
#include <errno.h>
#include <memory>
#include <string.h>
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::AdminAcceptHandler::AdminAcceptHandler(
const int listenSock,
io::PollReactor &reactor,
log::Logger &log,
Vdqm &vdqm,
DriveCatalogue &driveCatalogue,
const std::string &hostName)
throw():
m_listenSock(listenSock),
m_reactor(reactor),
m_log(log),
m_vdqm(vdqm),
m_driveCatalogue(driveCatalogue),
m_hostName(hostName),
m_netTimeout(1) {
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::AdminAcceptHandler::~AdminAcceptHandler()
throw() {
}
//------------------------------------------------------------------------------
// getFd
//------------------------------------------------------------------------------
int castor::tape::tapeserver::daemon::AdminAcceptHandler::getFd() throw() {
return m_listenSock;
}
//------------------------------------------------------------------------------
// fillPollFd
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::AdminAcceptHandler::fillPollFd(
struct pollfd &fd) throw() {
fd.fd = m_listenSock;
fd.events = POLLRDNORM;
fd.revents = 0;
}
//------------------------------------------------------------------------------
// handleEvent
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::AdminAcceptHandler::handleEvent(
const struct pollfd &fd) throw(castor::exception::Exception) {
checkHandleEventFd(fd.fd);
// Do nothing if there is no data to read
//
// POLLIN is unfortuntaley not the logical or of POLLRDNORM and POLLRDBAND
// on SLC 5. I therefore replaced POLLIN with the logical or. I also
// added POLLPRI into the mix to cover all possible types of read event.
if(0 == (fd.revents & POLLRDNORM) && 0 == (fd.revents & POLLRDBAND) &&
0 == (fd.revents & POLLPRI)) {
return;
}
// Accept the connection from the admin command
castor::utils::SmartFd connection;
try {
connection.reset(io::acceptConnection(fd.fd, 1));
} catch(castor::exception::Exception &ne) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to accept a connection from the admin command"
": " << ne.getMessage().str();
}
const legacymsg::TapeMsgBody job = readJobMsg(fd.fd);
logAdminJobReception(job);
const std::string unitName(job.drive);
const std::string dgn = m_driveCatalogue.getDgn(unitName);
if(CONF_UP==job.status) {
m_vdqm.setTapeDriveStatusUp(m_hostName, unitName, dgn);
}
else if(CONF_DOWN==job.status) {
m_vdqm.setTapeDriveStatusDown(m_hostName, unitName, dgn);
}
else {
castor::exception::Internal ex;
ex.getMessage() << "Wrong drive status requested:" << job.status;
throw ex;
}
m_reactor.removeHandler(this);
close(fd.fd);
}
//------------------------------------------------------------------------------
// checkHandleEventFd
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::AdminAcceptHandler::checkHandleEventFd(
const int fd) throw (castor::exception::Exception) {
if(m_listenSock != fd) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to accept connection from the admin command"
": Event handler passed wrong file descriptor"
": expected=" << m_listenSock << " actual=" << fd;
throw ex;
}
}
//------------------------------------------------------------------------------
// logAdminJobReception
//------------------------------------------------------------------------------
void
castor::tape::tapeserver::daemon::AdminAcceptHandler::logAdminJobReception(
const legacymsg::TapeMsgBody &job) const throw() {
log::Param params[] = {
log::Param("drive", job.drive),
log::Param("gid", job.gid),
log::Param("uid", job.uid),
log::Param("status", job.status)};
m_log(LOG_INFO, "Received message from admin command", params);
}
//------------------------------------------------------------------------------
// readJob
//------------------------------------------------------------------------------
castor::tape::legacymsg::TapeMsgBody
castor::tape::tapeserver::daemon::AdminAcceptHandler::readJobMsg(
const int connection) throw(castor::exception::Exception) {
const legacymsg::MessageHeader header = readJobMsgHeader(connection);
const legacymsg::TapeMsgBody body = readJobMsgBody(connection,
header.lenOrStatus);
return body;
}
//------------------------------------------------------------------------------
// readJobMsgHeader
//------------------------------------------------------------------------------
castor::tape::legacymsg::MessageHeader
castor::tape::tapeserver::daemon::AdminAcceptHandler::readJobMsgHeader(
const int connection) throw(castor::exception::Exception) {
// Read in the message header
char buf[3 * sizeof(uint32_t)]; // magic + request type + len
io::readBytes(connection, m_netTimeout, sizeof(buf), buf);
const char *bufPtr = buf;
size_t bufLen = sizeof(buf);
legacymsg::MessageHeader header;
memset(&header, '\0', sizeof(header));
legacymsg::unmarshal(bufPtr, bufLen, header);
if(TPMAGIC != header.magic) {
castor::exception::Internal ex;
ex.getMessage() << "Invalid admin job message: Invalid magic"
": expected=0x" << std::hex << TPMAGIC << " actual=0x" <<
header.magic;
throw ex;
}
if(TPCONF != header.reqType) {
castor::exception::Internal ex;
ex.getMessage() << "Invalid admin job message: Invalid request type"
": expected=0x" << std::hex << TPCONF << " actual=0x" <<
header.reqType;
throw ex;
}
// The length of the message body is checked later, just before it is read in
// to memory
return header;
}
//------------------------------------------------------------------------------
// readJobMsgBody
//------------------------------------------------------------------------------
castor::tape::legacymsg::TapeMsgBody
castor::tape::tapeserver::daemon::AdminAcceptHandler::readJobMsgBody(
const int connection, const uint32_t len)
throw(castor::exception::Exception) {
char buf[VDQM_MSGBUFSIZ];
if(sizeof(buf) < len) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to read body of job message"
": Maximum body length exceeded"
": max=" << sizeof(buf) << " actual=" << len;
throw ex;
}
try {
io::readBytes(connection, m_netTimeout, len, buf);
} catch(castor::exception::Exception &ne) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to read body of job message"
": " << ne.getMessage().str();
throw ex;
}
legacymsg::TapeMsgBody body;
const char *bufPtr = buf;
size_t bufLen = sizeof(buf);
legacymsg::unmarshal(bufPtr, bufLen, body);
return body;
}
/******************************************************************************
* castor/tape/tapeserver/daemon/AdminAcceptHandler.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author dkruse@cern.ch
*****************************************************************************/
#ifndef CASTOR_TAPE_TAPESERVER_DAEMON_ADMINACCEPTHANDLER_HPP
#define CASTOR_TAPE_TAPESERVER_DAEMON_ADMINACCEPTHANDLER_HPP 1
#include "castor/io/PollEventHandler.hpp"
#include "castor/io/PollReactor.hpp"
#include "castor/log/Logger.hpp"
#include "castor/tape/tapeserver/daemon/DriveCatalogue.hpp"
#include "castor/tape/tapeserver/daemon/Vdqm.hpp"
#include "castor/tape/legacymsg/MessageHeader.hpp"
#include "castor/tape/legacymsg/TapeMsgBody.hpp"
#include <poll.h>
namespace castor {
namespace tape {
namespace tapeserver {
namespace daemon {
/**
* Handles the events of the socket listening for connection from the admin
* commands.
*/
class AdminAcceptHandler: public io::PollEventHandler {
public:
/**
* Constructor.
*
* @param listenSock The file descriptor of the socket listening for
* connections from the vdqmd daemon.
* @param reactor The reactor to which new Vdqm connection handlers are to be
* registered.
* @param log The object representing the API of the CASTOR logging system.
* @param vdqm The object representing the vdqmd daemon.
* @param driveCatalogue The catalogue of tape drives controlled by the tape
* server daemon.
*/
AdminAcceptHandler(const int listenSock, io::PollReactor &reactor,
log::Logger &log, Vdqm &vdqm, DriveCatalogue &driveCatalogue, const std::string &hostName) throw();
/**
* Returns the integer file descriptor of this event handler.
*/
int getFd() throw();
/**
* Fills the specified poll file-descriptor ready to be used in a call to
* poll().
*/
void fillPollFd(struct pollfd &fd) throw();
/**
* Handles the specified event.
*
* @param fd The poll file-descriptor describing the event.
*/
void handleEvent(const struct pollfd &fd)
throw(castor::exception::Exception);
/**
* Destructor.
*/
~AdminAcceptHandler() throw();
private:
/**
* Throws an exception if the specified file-descriptor is not that of the
* socket listening for connections from the vdqmd daemon.
*/
void checkHandleEventFd(const int fd) throw (castor::exception::Exception);
/**
* Logs the reception of the specified job message from the vdqmd daemon.
*/
void logAdminJobReception(const legacymsg::TapeMsgBody &job)
const throw();
/**
* Reads a job message from the specified connection, sends back a positive
* acknowledgement and closes the connection.
*
* @param connection The file descriptor of the connection with the vdqm
* daemon.
* @return The job request from the vdqm.
*/
legacymsg::TapeMsgBody readJobMsg(const int connection)
throw(castor::exception::Exception);
/**
* Reads the header of a job message from the specified connection.
*
* @param connection The file descriptor of the connection with the vdqm
* daemon.
* @return The message header.
*/
legacymsg::MessageHeader readJobMsgHeader(const int connection)
throw(castor::exception::Exception);
/**
* Reads the body of a job message from the specified connection.
*
* @param connection The file descriptor of the connection with the vdqm
* daemon.
* @param len The length of the message body in bytes.
* @return The message body.
*/
legacymsg::TapeMsgBody readJobMsgBody(const int connection,
const uint32_t len) throw(castor::exception::Exception);
/**
* The file descriptor of the socket listening for connections from the vdqmd
* daemon.
*/
const int m_listenSock;
/**
* The reactor to which new Vdqm connection handlers are to be registered.
*/
io::PollReactor &m_reactor;