Commit 7607e229 authored by Eric Cano's avatar Eric Cano
Browse files

Creation of new tape server session.

Created a bare-bones tape session with corresponding harness in a unit test.
Successfuly retrives the volume id from a client thread.
parent b3b2406b
add_executable(tapeserverd tapeserverd.cpp)
target_link_libraries(tapeserverd Exception SCSI System Utils File castorcommon
castorclient)
\ No newline at end of file
castorclient)
add_library(tapeserver tapeSession.cpp)
add_library(tapeserverdTest
clientSimulator.cpp
../../tpcp/TpcpCommand.cpp
../../tpcp/StreamOperators.cpp
../../tpcp/Helper.cpp
../../tpcp/TapeFseqRange.cpp)
\ No newline at end of file
/******************************************************************************
* clientSimulator.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 Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#include <typeinfo>
#include <memory>
#include "clientSimulator.hpp"
#include "../../tapegateway/GatewayMessage.hpp"
#include "castor/tape/tapegateway/Volume.hpp"
#include "castor/tape/tapegateway/EndNotificationErrorReport.hpp"
using namespace castor::tape::server;
using namespace castor::tape;
clientSimulator::clientSimulator(uint32_t volReqId, std::string vid):
TpcpCommand("clientSimulator::clientSimulator"), m_vid(vid)
{
m_volReqId = volReqId;
setupCallbackSock();
}
void clientSimulator::processFirstRequest()
throw (castor::exception::Exception) {
// Accept the next connection
std::auto_ptr<castor::io::ServerSocket> clientConnection(m_callbackSock.accept());
// Read in the message sent by the tapebridge
std::auto_ptr<castor::IObject> obj(clientConnection->readObject());
// Cast the message to a GatewayMessage or die
tapegateway::GatewayMessage & msg(
dynamic_cast<tapegateway::GatewayMessage &> (*obj.get()));
// Check the mount transaction ID
if (msg.mountTransactionId() != (uint64_t) m_volReqId) {
std::stringstream oss;
oss <<
"Mount transaction ID mismatch" <<
": actual=" << msg.mountTransactionId() <<
" expected=" << m_volReqId;
sendEndNotificationErrorReport(msg.aggregatorTransactionId(), EBADMSG,
oss.str(), *clientConnection);
castor::exception::Exception ex(EBADMSG);
ex.getMessage() << oss.str();
throw ex;
}
// We strictly expect getVolId for this test for the moment
if (msg.type() != tapegateway::VolumeRequest::TYPE()) {
std::stringstream oss;
oss <<
"Expected a tapegateway::VolumeRequest, got " << typeid (msg).name();
sendEndNotificationErrorReport(msg.aggregatorTransactionId(), EBADMSG,
oss.str(), *clientConnection);
castor::exception::Exception ex(EBADMSG);
ex.getMessage() << oss.str();
throw ex;
}
// This should always succeed
tapegateway::VolumeRequest & vReq =
dynamic_cast<tapegateway::VolumeRequest &> (msg);
tapegateway::Volume vol;
vol.setAggregatorTransactionId(vReq.aggregatorTransactionId());
vol.setVid(m_vid);
vol.setClientType(tapegateway::READ_TP);
vol.setMode(castor::tape::tapegateway::READ);
vol.setLabel(m_volLabel);
vol.setMountTransactionId(m_volReqId);
vol.setDensity(m_density);
clientConnection->sendObject(vol);
}
void clientSimulator::sendEndNotificationErrorReport(
const uint64_t tapebridgeTransactionId,
const int errorCode,
const std::string &errorMessage,
castor::io::AbstractSocket &sock)
throw () {
tapegateway::EndNotificationErrorReport err;
err.setAggregatorTransactionId(tapebridgeTransactionId);
err.setErrorCode(errorCode);
err.setErrorMessage(errorMessage);
sock.sendObject(err);
}
\ No newline at end of file
/******************************************************************************
* clientSimulator.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 Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#pragma once
#include "../../tpcp/TpcpCommand.hpp"
namespace castor {
namespace tape {
namespace server {
/**
* A class, reusing code of TpcpCommand which simulates the tapebridge
* part of the client communication with the server. The constructor
* will hence setup a client callback socket and wait. All the tape mounting
* logic is hence skipped. We will then in parallel start a tape session.
*/
class clientSimulator: public tpcp::TpcpCommand {
public:
clientSimulator(uint32_t volReqId, std::string vid);
virtual ~clientSimulator() throw () {}
struct ipPort {
ipPort(uint32_t i, uint16_t p): ip(i), port(p) {}
uint32_t ip;
uint16_t port;
};
struct ipPort getCallbackAddress() {
unsigned short port = 0;
/* This is a workaround for the usage of unsigned long for ips in castor
* (it's not fine anymore on 64 bits systems).
*/
unsigned long ip = 0;
m_callbackSock.getPortIp(port, ip);
return ipPort(ip,port);
}
void sessionLoop() {
processFirstRequest();
}
protected:
// Place holders for pure virtual members of TpcpCommand we don't
// use in the simulator
virtual void usage(std::ostream &) const throw () {}
virtual void parseCommandLine(const int, char **)
throw(castor::exception::Exception) {}
virtual void checkAccessToDisk()
const throw(castor::exception::Exception) {}
virtual void checkAccessToTape()
const throw(castor::exception::Exception) {}
virtual void requestDriveFromVdqm(char *const)
throw(castor::exception::Exception) {}
virtual void performTransfer() throw(castor::exception::Exception) {}
// The functions we actually implement in the simulator
virtual void sendVolumeToTapeBridge(
const tapegateway::VolumeRequest &volumeRequest,
castor::io::AbstractTCPSocket &connection)
const throw(castor::exception::Exception) {}
virtual bool dispatchMsgHandler(castor::IObject *const obj,
castor::io::AbstractSocket &sock) throw(castor::exception::Exception) {
return false;
}
private:
// Process the first request which should be getVolume
void processFirstRequest() throw(castor::exception::Exception);
// Notify the client
void sendEndNotificationErrorReport(
const uint64_t tapebridgeTransactionId,
const int errorCode,
const std::string &errorMessage,
castor::io::AbstractSocket &sock)
throw();
std::string m_vid;
std::string m_volLabel;
std::string m_density;
};
}
}
}
/******************************************************************************
* tapeSession.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 Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#include <memory>
#include "tapeSession.hpp"
#include "castor/io/ClientSocket.hpp"
#include "castor/tape/tapegateway/VolumeRequest.hpp"
#include "castor/tape/tapegateway/Volume.hpp"
using namespace castor::tape;
castor::IObject *
castor::tape::server::tapeSession::requestReplySession(
tapegateway::GatewayMessage &req) {
// Open connection to client
castor::io::ClientSocket clientConnection(m_client.port, m_client.ip);
clientConnection.connect();
clientConnection.sendObject(req);
castor::IObject * ret = clientConnection.readObject();
return ret;
}
void castor::tape::server::tapeSession::getVolume() {
tapegateway::VolumeRequest volReq;
volReq.setMountTransactionId(m_mountTransactionId);
std::auto_ptr<castor::IObject> reply(requestReplySession(volReq));
// Get a Volume object or die
tapegateway::Volume & vol = dynamic_cast<tapegateway::Volume &>(*reply);
m_vid = vol.vid();
}
\ No newline at end of file
/******************************************************************************
* tapeSession.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 Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#pragma once
#include <sys/socket.h>
#include <stdint.h>
#include <string>
#include "../../tapegateway/GatewayMessage.hpp"
namespace castor {
namespace tape {
namespace server {
class tapeSession {
public:
tapeSession(uint32_t client_ip, uint16_t client_port,
uint64_t mountTransactionId):
m_client(client_ip, client_port),
m_mountTransactionId(mountTransactionId) {}
std::string m_vid;
void getVolume();
private:
castor::IObject *
requestReplySession(castor::tape::tapegateway::GatewayMessage &req);
// Address of the client (in terms of tape server, as it's a TCP SERVER)
struct clientAddr {
clientAddr(uint32_t cip, uint16_t cport):
ip(cip), port(cport) {}
uint32_t ip;
uint16_t port;
} m_client;
uint64_t m_mountTransactionId;
};
}
}
}
/******************************************************************************
* tapeserverdTest.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 Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#include <gtest/gtest.h>
#include "clientSimulator.hpp"
#include "tapeSession.hpp"
#include "../threading/Threading.hpp"
using namespace castor::tape::server;
namespace unitTest {
class clientRunner: public castor::tape::threading::Thread {
public:
clientRunner(clientSimulator &client): m_sim(client) {}
private:
void run() {
m_sim.sessionLoop();
}
clientSimulator & m_sim;
};
TEST(tapeServer, simpleGetVol) {
// TpcpClients only supports 32 bits session number
// This number has to be less than 2^31 as in addition there is a mix
// of signed and unsigned numbers
// As the current ids in prod are ~30M, we are far from overflow (Feb 2013)
uint32_t volReq = 0xBEEF;
std::string vid = "V12345";
clientSimulator sim(volReq, vid);
struct clientSimulator::ipPort clientAddr = sim.getCallbackAddress();
clientRunner simRun(sim);
simRun.start();
tapeSession sess(clientAddr.ip, clientAddr.port, volReq);
sess.getVolume();
simRun.wait();
ASSERT_EQ("V12345", sess.m_vid);
}
}
......@@ -46,10 +46,13 @@ target_link_libraries(castorUnitTests TapeDrive Exception SCSI System Utils File
add_executable(castorThreadedUnitTests
castorUnitTests.cpp
../castor/tape/tapeserver/threading/ThreadingMTTests.cpp
../castor/tape/tapeserver/daemon/tapeserverdTest.cpp
)
target_link_libraries(castorThreadedUnitTests TapeDrive Exception SCSI System
Utils File castorTapeServerThreading
${GTEST_LIBRARY} gmock pthread castorcommon castorclient)
Utils File castorTapeServerThreading tapeserverdTest tapeserver
castortapegatewayprotocol castortapenet castortapeutils
${GTEST_LIBRARY} gmock pthread castorcommon castorclient castorvdqm
castorvmgr castorrfio)
# Those tests are multi threaded. They could should also be run in
# helgrind/drd (but not memcheck)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment