Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
dCache
cta
Commits
a7ba6f1d
Commit
a7ba6f1d
authored
Apr 29, 2014
by
Daniele Kruse
Browse files
Added SetVidRequestMsgBody
parent
e4d23cbb
Changes
24
Hide whitespace changes
Inline
Side-by-side
castor/legacymsg/CMakeLists.txt
View file @
a7ba6f1d
...
...
@@ -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
0 → 100644
View file @
a7ba6f1d
/******************************************************************************
* 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
0 → 100644
View file @
a7ba6f1d
/******************************************************************************
* 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
castor/legacymsg/TapeMarshal.cpp
View file @
a7ba6f1d
...
...
@@ -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
//-----------------------------------------------------------------------------
...
...
castor/legacymsg/TapeMarshal.hpp
View file @
a7ba6f1d
...
...
@@ -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.
...
...
castor/legacymsg/TapeMarshalTest.cpp
View file @
a7ba6f1d
...
...
@@ -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
castor/tape/tapeserver/daemon/CMakeLists.txt
View file @
a7ba6f1d
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
...
...
castor/tape/tapeserver/daemon/Constants.hpp
View file @
a7ba6f1d
...
...
@@ -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
...
...
castor/tape/tapeserver/daemon/DriveCatalogue.cpp
View file @
a7ba6f1d
...
...
@@ -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 devi
d
e type of tape drive "
<<
unitName
<<
ex
.
getMessage
()
<<
"Failed to get devi
c
e 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
//-----------------------------------------------------------------------------
...
...
castor/tape/tapeserver/daemon/DriveCatalogue.hpp
View file @
a7ba6f1d
...
...
@@ -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
e
example: /dev/nst0
* The device file of the tape drive, for example: /dev/nst0
*/
std
::
string
devFilename
;
...
...
castor/tape/tapeserver/daemon/DummyTapeserver.cpp
0 → 100644
View file @
a7ba6f1d
/******************************************************************************
* 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
0 → 100644
View file @
a7ba6f1d
/******************************************************************************
* 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
0 → 100644
View file @
a7ba6f1d
/******************************************************************************
* 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
;