Commit a7ba6f1d authored by Daniele Kruse's avatar Daniele Kruse
Browse files

Added SetVidRequestMsgBody

parent e4d23cbb
......@@ -50,6 +50,7 @@ set (TAPE_LEGACYMSG_LIB_SRC_FILES
RtcpSegmentAttributes.cpp
RtcpTapeRqstMsgBody.cpp
ScsiLibrarySlot.cpp
SetVidRequestMsgBody.cpp
TapeBridgeMarshal.cpp
TapeConfigRequestMsgBody.cpp
TapeMarshal.cpp
......
/******************************************************************************
* castor/legacymsg/SetVidRequestMsgBody.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/legacymsg/SetVidRequestMsgBody.hpp"
#include <string.h>
castor::legacymsg::SetVidRequestMsgBody::SetVidRequestMsgBody() throw() {
memset(vid, '\0', sizeof(vid));
memset(drive, '\0', sizeof(drive));
}
/******************************************************************************
* castor/legacymsg/SetVidRequestMsgBody.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
*****************************************************************************/
#pragma once
#include "h/Castor_limits.h"
#include <stdint.h>
namespace castor {
namespace legacymsg {
/**
* An update-VID message, used to update the drive catalogue with the contents of a drive.
*/
struct SetVidRequestMsgBody {
/**
* The VID of the tape inside the drive ("" if empty)
*/
char vid[CA_MAXVIDLEN+1];
/**
* The drive name (a.k.a. unit name)
*/
char drive[CA_MAXUNMLEN+1];
/**
* Constructor: zeroes the two strings.
*/
SetVidRequestMsgBody() throw();
}; // struct SetVidRequestMsgBody
} // namespace legacymsg
} // namespace castor
......@@ -152,6 +152,70 @@ size_t castor::legacymsg::marshal(char *const dst, const size_t dstLen, const Ta
return totalLen;
}
//-----------------------------------------------------------------------------
// marshal
//-----------------------------------------------------------------------------
size_t castor::legacymsg::marshal(char *const dst, const size_t dstLen, const SetVidRequestMsgBody &src) throw(castor::exception::Exception) {
if(dst == NULL) {
castor::exception::Exception ex(EINVAL);
ex.getMessage() << "Failed to marshal TapeConfigRequestMsgBody"
": Pointer to destination buffer is NULL";
throw ex;
}
// Calculate the length of the message body
const uint32_t len =
strlen(src.vid) + 1 + // vid
strlen(src.drive) + 1; // drive
// Calculate the total length of the message (header + body)
// Message header = magic + reqType + len = 3 * sizeof(uint32_t)
const size_t totalLen = 3 * sizeof(uint32_t) + len;
// Check that the message buffer is big enough
if(totalLen > dstLen) {
castor::exception::Exception ex(EMSGSIZE);
ex.getMessage() << "Failed to marshal TapeConfigRequestMsgBody"
": Buffer too small: required=" << totalLen << " actual=" << dstLen;
throw ex;
}
// Marshall message header
char *p = dst;
io::marshalUint32(TPMAGIC, p); // Magic number
io::marshalUint32(SETVID, p); // Request type
char *msg_len_field_pointer = p;
io::marshalUint32(0, p); // Temporary length
// Marshall message body
io::marshalString(src.vid, p);
io::marshalString(src.drive, p);
// Calculate the number of bytes actually marshalled
const size_t nbBytesMarshalled = p - dst;
io::marshalUint32(nbBytesMarshalled, msg_len_field_pointer); // Actual length
// Check that the number of bytes marshalled was what was expected
if(totalLen != nbBytesMarshalled) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to marshal SetVidRequestMsgBody"
": Mismatch between expected total length and actual"
": expected=" << totalLen << "actual=" << nbBytesMarshalled;
throw ex;
}
return totalLen;
}
//-----------------------------------------------------------------------------
// unmarshal
//-----------------------------------------------------------------------------
void castor::legacymsg::unmarshal(const char * &src, size_t &srcLen, SetVidRequestMsgBody &dst) throw(castor::exception::Exception) {
io::unmarshalString(src, srcLen, dst.vid);
io::unmarshalString(src, srcLen, dst.drive);
}
//-----------------------------------------------------------------------------
// unmarshal
//-----------------------------------------------------------------------------
......
......@@ -28,6 +28,7 @@
#include "castor/exception/Exception.hpp"
#include "castor/legacymsg/TapeConfigRequestMsgBody.hpp"
#include "castor/legacymsg/TapeStatRequestMsgBody.hpp"
#include "castor/legacymsg/SetVidRequestMsgBody.hpp"
#include <errno.h>
#include <stdint.h>
......@@ -59,6 +60,32 @@ size_t marshal(char *const dst, const size_t dstLen, const TapeConfigRequestMsgB
*/
size_t marshal(char *const dst, const size_t dstLen, const TapeStatRequestMsgBody &src) throw(castor::exception::Exception);
/**
* Marshals the specified source message body structure and its implicit
* header into the specified destination buffer.
*
* @param dst The destination message buffer.
* @param dstLen The length of the destination buffer.
* @param src The source structure.
* @return The total length of the message (header + body).
*/
size_t marshal(char *const dst, const size_t dstLen, const SetVidRequestMsgBody &src) throw(castor::exception::Exception);
/**
* 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, SetVidRequestMsgBody &dst) throw(castor::exception::Exception);
/**
* Unmarshals a message body with the specified destination structure type
* from the specified source buffer.
......
......@@ -139,4 +139,50 @@ TEST_F(castor_legacymsg_TapeMarshalTest, marshalTapeStatRequestMsgBody) {
}
}
TEST_F(castor_legacymsg_TapeMarshalTest, marshalSetVidRequestMsgBody) {
using namespace castor::legacymsg;
char buf[80]; // Expect message (header + body) to occupy exactly 80 bytes
SetVidRequestMsgBody srcMsgBody;
// Marshal entire message (header + body)
{
castor::utils::copyString(srcMsgBody.vid, "XXXXXX");
castor::utils::copyString(srcMsgBody.drive, "HELLO");
size_t bufLen = sizeof(buf);
size_t totalLen = 0; // Total length of message (header + body)
ASSERT_NO_THROW(totalLen = marshal(buf, bufLen, srcMsgBody));
ASSERT_EQ((uint32_t)25, totalLen);
}
// Unmarshall message header
{
MessageHeader dstHeader;
const char *bufPtr = buf;
size_t bufLen = 12; // Length of the message header
ASSERT_NO_THROW(unmarshal(bufPtr, bufLen, dstHeader));
ASSERT_EQ(buf + 12, bufPtr);
ASSERT_EQ((size_t)0, bufLen);
ASSERT_EQ((uint32_t)TPMAGIC, dstHeader.magic);
ASSERT_EQ((uint32_t)SETVID, dstHeader.reqType);
ASSERT_EQ((uint32_t)25, dstHeader.lenOrStatus);
}
// Unmarshall message body
{
SetVidRequestMsgBody dstMsgBody;
const char *bufPtr = buf + 12; // Point at beginning of message body
size_t bufLen = 13; // Length of the message body
ASSERT_NO_THROW(unmarshal(bufPtr, bufLen, dstMsgBody));
ASSERT_EQ(buf + 25, bufPtr);
ASSERT_EQ((size_t)0, bufLen);
ASSERT_EQ(std::string("XXXXXX"), dstMsgBody.drive);
ASSERT_EQ(std::string("HELLO"), dstMsgBody.drive);
}
}
} // namespace unitTests
add_executable(tapeserverd
AdminAcceptHandler.cpp
MountSessionAcceptHandler.cpp
DebugMountSessionForVdqmProtocol.cpp
DriveCatalogue.cpp
TapeDaemon.cpp
TapeDaemonMain.cpp
VdqmAcceptHandler.cpp
VdqmConnectionHandler.cpp)
VdqmConnectionHandler.cpp
TapeserverProxy.cpp
TapeserverProxyImpl.cpp)
target_link_libraries(tapeserverd
Exception
......
......@@ -39,6 +39,12 @@ const unsigned short TAPE_SERVER_VDQM_LISTENING_PORT = 5070;
*/
const unsigned short TAPE_SERVER_ADMIN_LISTENING_PORT = 5011;
/**
* The TCP/IP port on which the tape server daemon listens for incoming
* connections from the mount session.
*/
const unsigned short TAPE_SERVER_MOUNTSESSION_LISTENING_PORT = 54321;
} // namespace daemon
} // namespace tapeserver
} // namespace tape
......
......@@ -27,6 +27,7 @@
#include "castor/utils/utils.hpp"
#include <string.h>
#include <time.h>
//-----------------------------------------------------------------------------
// drvState2Str
......@@ -359,7 +360,7 @@ const std::string &
DriveMap::const_iterator itor = m_drives.find(unitName);
if(m_drives.end() == itor) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to get devide type of tape drive " << unitName <<
ex.getMessage() << "Failed to get device type of tape drive " << unitName <<
": Unknown drive";
throw ex;
}
......@@ -367,6 +368,24 @@ const std::string &
return itor->second.devType;
}
//-----------------------------------------------------------------------------
// updateVidAssignment
//-----------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::DriveCatalogue::updateVidAssignment(const std::string &vid, const std::string &unitName) throw(castor::exception::Exception) {
std::ostringstream task;
task << "update the VID of tape drive " << unitName;
DriveMap::iterator itor = m_drives.find(unitName);
if(m_drives.end() == itor) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to " << task.str() << ": Unknown drive";
throw ex;
}
itor->second.vid = vid;
itor->second.assignment_time = time(0); // set to "now"
}
//-----------------------------------------------------------------------------
// configureUp
//-----------------------------------------------------------------------------
......
......@@ -332,6 +332,14 @@ public:
* @param unitName The unit name of the tape drive.
*/
void mountSessionFailed(const std::string &unitName) throw(castor::exception::Exception);
/**
* Updates the vid and assignment time of the specified drive
*
* @param vid Volume ID of the tape mounted
* @param unitName Name of the drive
*/
void updateVidAssignment(const std::string &vid, const std::string &unitName) throw(castor::exception::Exception);
private:
......@@ -344,9 +352,19 @@ private:
* /etc/castor/TPCONFIG.
*/
std::string dgn;
/**
* The Volume ID of the tape mounted in the drive. Empty string if drive is empty.
*/
std::string vid;
/**
* The point in time when the drive has been assigned a tape
*/
time_t assignment_time;
/**
* The device file of the tape drive, for eexample: /dev/nst0
* The device file of the tape drive, for example: /dev/nst0
*/
std::string devFilename;
......
/******************************************************************************
* castor/tape/tapeserver/daemon/DummyTapeserver.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/tapeserver/daemon/DummyTapeserver.hpp"
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::DummyTapeserver::DummyTapeserver() throw() {
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::DummyTapeserver::~DummyTapeserver() throw() {
}
//------------------------------------------------------------------------------
// setVidInDriveCatalogue
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::DummyTapeserver::setVidInDriveCatalogue(const std::string &vid, const std::string &unitName) throw(castor::exception::Exception) {
}
/******************************************************************************
* castor/tape/tapeserver/daemon/DummyTapeserver.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
*****************************************************************************/
#pragma once
#include "castor/log/Logger.hpp"
#include "castor/legacymsg/MessageHeader.hpp"
#include "castor/legacymsg/SetVidRequestMsgBody.hpp"
#include "castor/tape/tapeserver/daemon/TapeserverProxy.hpp"
namespace castor {
namespace tape {
namespace tapeserver {
namespace daemon {
/**
* A concrete implementation of the interface to the vdqm daemon.
*/
class DummyTapeserver: public TapeserverProxy {
public:
/**
* Constructor.
*/
DummyTapeserver() throw();
/**
* Destructor.
*
* Closes the listening socket created in the constructor to listen for
* connections from the vdqmd daemon.
*/
~DummyTapeserver() throw();
/**
* Sets the VID of the tape mounted in the specified tape drive.
*
* @param vid The Volume ID of the tape in the tape drive
* @param unitName The unit name of the tape drive.
*/
void setVidInDriveCatalogue(const std::string &vid, const std::string &unitName) throw(castor::exception::Exception);
}; // class TapeserverProxyImpl
} // namespace daemon
} // namespace tapeserver
} // namespace tape
} // namespace castor
/******************************************************************************
* castor/tape/tapeserver/daemon/MountSessionAcceptHandler.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/MountSessionAcceptHandler.hpp"
#include "castor/utils/SmartFd.hpp"
#include "h/common.h"
#include "h/serrno.h"
#include "h/Ctape.h"
#include "castor/legacymsg/CommonMarshal.hpp"
#include "castor/legacymsg/TapeMarshal.hpp"
#include "castor/tape/utils/utils.hpp"
#include "DriveCatalogue.hpp"
#include <vdqm_api.h>
#include <errno.h>
#include <memory>
#include <string.h>
#include <list>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::MountSessionAcceptHandler::MountSessionAcceptHandler(
const int fd, io::PollReactor &reactor, log::Logger &log,
DriveCatalogue &driveCatalogue, const std::string &hostName)
throw():
m_fd(fd),
m_reactor(reactor),
m_log(log),
m_driveCatalogue(driveCatalogue),
m_hostName(hostName),
m_netTimeout(10) {
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::MountSessionAcceptHandler::~MountSessionAcceptHandler()
throw() {
}
//------------------------------------------------------------------------------
// getFd
//------------------------------------------------------------------------------
int castor::tape::tapeserver::daemon::MountSessionAcceptHandler::getFd() throw() {
return m_fd;
}
//------------------------------------------------------------------------------
// fillPollFd
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::MountSessionAcceptHandler::fillPollFd(
struct pollfd &fd) throw() {
fd.fd = m_fd;
fd.events = POLLRDNORM;
fd.revents = 0;
}
//-----------------------------------------------------------------------------
// marshalTapeConfigReplyMsg
//-----------------------------------------------------------------------------
size_t castor::tape::tapeserver::daemon::MountSessionAcceptHandler::marshalSetVidReplyMsg(char *const dst, const size_t dstLen,
const int rc)
throw(castor::exception::Exception) {
if(dst == NULL) {
TAPE_THROW_CODE(EINVAL,
": Pointer to destination buffer is NULL");
}
// Calculate the length of the message header
const uint32_t totalLen = (2 * sizeof(uint32_t)) + sizeof(int32_t); // magic + reqType + returnCode
// Check that the message header buffer is big enough
if(totalLen > dstLen) {
TAPE_THROW_CODE(EMSGSIZE,
": Buffer too small for reply message"
": Required size: " << totalLen <<
": Actual size: " << dstLen);
}
// Marshal the message header
char *p = dst;
io::marshalUint32(TPMAGIC, p);
io::marshalUint32(TAPERC, p);
io::marshalInt32(rc, p);
// Calculate the number of bytes actually marshalled
const size_t nbBytesMarshalled = p - dst;
// Check that the number of bytes marshalled was what was expected
if(totalLen != nbBytesMarshalled) {