diff --git a/CMakeLists.txt b/CMakeLists.txt
index b18e84fb3c36a6318bfca652835b8836f51ebadf..b49e3b51a16122cdb917b108771dbc9bfb095154 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,21 +42,6 @@ ELSE(DEFINED PackageOnly)
     message (STATUS "Already set: COMPILE_PACKAGING=${COMPILE_PACKAGING}")
   endif (NOT DEFINED COMPILE_PACKAGING)
 
-
-  # With the exception of shared-library plugins, the CASTOR rpms only install the
-  # /usr/lib64/libcastor*.so symbolic links for libraries used by end-user
-  # developers.  Therefore the locations of the internal CASTOR libraries required
-  # by tapeserved and not by end-user developers need to be imported into cmake.
-  add_library(castorlegacymsg SHARED IMPORTED)
-  set_target_properties(castorlegacymsg PROPERTIES
-    IMPORTED_LOCATION /usr/lib64/libcastorlegacymsg.so.2.1)
-  add_library(castorserver SHARED IMPORTED)
-  set_target_properties(castorserver PROPERTIES
-    IMPORTED_LOCATION /usr/lib64/libcastorserver.so.2.1)
-  add_library(castortapegatewayprotocol SHARED IMPORTED)
-  set_target_properties(castortapegatewayprotocol PROPERTIES
-    IMPORTED_LOCATION /usr/lib64/libcastortapegatewayprotocol.so.2.1)
-
   IF(NOT CMAKE_BUILD_TYPE STREQUAL "")
     # If the user specifies -DCMAKE_BUILD_TYPE on the command line, take their definition and dump it in the cache
     message(STATUS "Setting build type to ${CMAKE_BUILD_TYPE} as requested.")
@@ -119,10 +104,5 @@ configure_file(tests/valgrind.suppr tests/valgrind.suppr COPYONLY)
 add_custom_target(test tests/unittests
                     #  
                     COMMAND valgrind --track-fds=yes --leak-check=full --demangle=yes --gen-suppressions=all --show-reachable=yes --error-exitcode=1 --suppressions=tests/valgrind.suppr tests/unittests
-                    #COMMAND test/castorThreadedUnitTests
-                    #COMMAND valgrind --track-fds=yes --leak-check=full --show-reachable=yes --error-exitcode=1  test/castorThreadedUnitTests
-                    #COMMAND valgrind --tool=helgrind -v --demangle=no --conflict-cache-size=30000000 --error-exitcode=1 test/castorThreadedUnitTests
-                    #COMMAND test/castorMultiprocessUnitTests
-                    #COMMAND valgrind --tool=helgrind --error-exitcode=1 test/castorMultiprocessUnitTests 
-                    DEPENDS tests/unittests #test/castorThreadedUnitTests test/castorMultiprocessUnitTests test/castorThreadedUnitTests.supp
+                    DEPENDS tests/unittests tests/valgrind.suppr
                     COMMENT "Running unit tests" VERBATIM)
diff --git a/cmdline/CMakeLists.txt b/cmdline/CMakeLists.txt
index 2383645201cbfc549dcce7fbf43987dc83b6e472..1a79ff46f9d7f55e08d3f98454ee0d09b7c43696 100644
--- a/cmdline/CMakeLists.txt
+++ b/cmdline/CMakeLists.txt
@@ -9,7 +9,7 @@ target_link_libraries (cta ${XROOTD_XRDCL_LIB} ctacommon cryptopp)
 
 include_directories (${CMAKE_SOURCE_DIR}/tapeserver/)
 add_executable (ctaAddAdminUser CTAAddAdminUser.cpp )
-target_link_libraries (ctaAddAdminUser ctacommon castorserver ctalog 
+target_link_libraries (ctaAddAdminUser ctacommon ctalog 
   castorcommon ctautils protobuf ctascheduler ctanameserver)
 
 install (TARGETS cta ctaAddAdminUser DESTINATION usr/bin)
diff --git a/tapeserver/castor/io/CMakeLists.txt b/tapeserver/castor/io/CMakeLists.txt
index aff418d2eb4552dff307f2f24ba3225c6016fb25..9c65106fd2bbb21b738c8027b6d56f35fb9cf55b 100644
--- a/tapeserver/castor/io/CMakeLists.txt
+++ b/tapeserver/castor/io/CMakeLists.txt
@@ -3,7 +3,12 @@ cmake_minimum_required (VERSION 2.6)
 include_directories(${PROJECT_SOURCE_DIR}/tapeserver)
 include_directories(${PROJECT_SOURCE_DIR}/tapeserver/h)
 
+add_library (ctaio
+  io.cpp
+  IpAndPort.cpp
+  StreamAddress.cpp)
+
 add_library (ctaiounittests SHARED
   IoTest.cpp)
 target_link_libraries (ctaiounittests
-  castorclient)
+  ctaio)
diff --git a/tapeserver/castor/io/StreamAddress.cpp b/tapeserver/castor/io/StreamAddress.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..60677e930d2bbae3f1ffc8a08bfccfcdfe6749e4
--- /dev/null
+++ b/tapeserver/castor/io/StreamAddress.cpp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * 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 Files
+#include "StreamAddress.hpp"
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+castor::io::StreamAddress::StreamAddress(castor::io::biniostream& stream,
+                                         const std::string cnvSvcName,
+                                         const unsigned int cnvSvcType) :
+  BaseAddress(), m_stream(stream) {
+  setCnvSvcName(cnvSvcName);
+  setCnvSvcType(cnvSvcType);  
+}
diff --git a/tapeserver/castor/io/StreamAddress.hpp b/tapeserver/castor/io/StreamAddress.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ff8d2ba15fd6c33191c9bc291ce02f277b6dea67
--- /dev/null
+++ b/tapeserver/castor/io/StreamAddress.hpp
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * 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 Files
+#include "castor/io/biniostream.h"
+#include "castor/BaseAddress.hpp"
+#include "castor/Constants.hpp"
+
+namespace castor {
+
+  namespace io {
+
+    /**
+     * An address containing a reference to a binary stream
+     */
+    class StreamAddress : public BaseAddress {
+
+    public:
+
+      /**
+       * constructor
+       * @param stream the stream where to put the data
+       * @param cnvSvcName the conversion service able to deal with this address
+       * In this later case, the type will be deduced from the id.
+       */
+      StreamAddress(biniostream& stream,
+                    const std::string cnvSvcName,
+                    const unsigned int cnvSvcType);
+
+      /*
+       * destructor
+       */
+      virtual ~StreamAddress() throw() {}
+
+      /**
+       * gets the id of this address
+       */
+      virtual biniostream& stream() const { return m_stream; }
+      
+    private:
+
+      /**
+       * the id of this address
+       */
+      biniostream& m_stream;
+
+    };
+
+  } // end of namespace io
+
+} // end of namespace castor
+
diff --git a/tapeserver/castor/io/biniostream.h b/tapeserver/castor/io/biniostream.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1f7e84fdfafb445bdaca9d8ce0edc50e67a59b4
--- /dev/null
+++ b/tapeserver/castor/io/biniostream.h
@@ -0,0 +1,311 @@
+/******************************************************************************
+ *
+ * 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 <sstream>
+#include "osdep.h"
+#include "castor/exception/OutOfMemory.hpp"
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __APPLE__
+#define __bswap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
+#define __bswap_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) | (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
+#else
+#include <byteswap.h>
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+/* The host byte order is the same as the "inverted network byte order",
+   which is the reference used by Castor production setup,
+   so these functions are all just identity.  */
+#define intohl(x)       (x)
+#define intohs(x)       (x)
+#define htoinl(x)       (x)
+#define htoins(x)       (x)
+
+#else
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define intohl(x)     __bswap_32 (x)
+#define intohs(x)     __bswap_16 (x)
+#define htoinl(x)     __bswap_32 (x)
+#define htoins(x)     __bswap_16 (x)
+#endif
+#endif
+
+namespace castor {
+
+  namespace io {
+
+    /**
+     * A binary stream based on stringstream
+     */
+    class biniostream : public std::stringstream {
+    public:
+      biniostream(std::string& s) : std::stringstream(s) {}
+      biniostream() : std::stringstream() {}
+
+      biniostream& operator<< (char c) {
+        write((char*)&c, sizeof(char));
+        return *this;
+      }
+
+      biniostream& operator<< (unsigned char c) {
+        write((char*)&c, sizeof(unsigned char));
+        return *this;
+      }
+
+      biniostream& operator<< (signed char c) {
+        write((char*)&c, sizeof(signed char));
+        return *this;
+      }
+
+      biniostream& operator<< (int i) {
+        i = htoinl((unsigned int)i);
+        write((char*)&i, sizeof(int));
+        return *this;
+      }
+
+      biniostream& operator<< (unsigned int i) {
+        i = htoinl(i);
+        write((char*)&i, sizeof(unsigned int));
+        return *this;
+      }
+
+      biniostream& operator<< (short s) {
+        s = htoins((unsigned short)s);
+        write((char*)&s, sizeof(short));
+        return *this;
+      }
+
+      biniostream& operator<< (unsigned short s) {
+        s = htoins(s);
+        write((char*)&s, sizeof(unsigned short));
+        return *this;
+      }
+
+      biniostream& operator<< (long l) {
+        l = htoinl((unsigned long)l);
+        write((char*)&l, LONGSIZE);
+        return *this;
+      }
+
+      biniostream& operator<< (unsigned long l) {
+        l = htoinl(l);
+        write((char*)&l, LONGSIZE);
+        return *this;
+      }
+
+      biniostream& operator<< (const char* cp) {
+        int len = strlen(cp)+1;
+        write((char*)&len, sizeof(int));
+        write(cp,len);
+        return *this;
+      }
+
+      biniostream& operator<< (bool b) {
+        write((char*)&b, sizeof(bool));
+        return *this;
+      }
+
+      biniostream& operator<< (float f) {
+        write((char*)&f, sizeof(float));
+        return *this;
+      }
+
+      biniostream& operator<< (double d) {
+        write((char*)&d, sizeof(double));
+        return *this;
+      }
+
+      biniostream& operator<< (long double d) {
+        write((char*)&d, sizeof(long double));
+        return *this;
+      }
+
+      biniostream& operator<< (u_signed64 d) {
+        unsigned long n = (unsigned long)d;   // Least significant part first
+        write((char*)&n, LONGSIZE);
+        n = htoinl((unsigned long)(d >> 32));
+        write((char*)&n, LONGSIZE);
+        return *this;
+      }
+
+      biniostream& operator<< (signed64 d) {
+        unsigned long n = (unsigned long)d;   // Least significant part first
+        write((char*)&n, LONGSIZE);
+        n = htoinl((unsigned long)(d >> 32));
+        write((char*)&n, LONGSIZE);
+        return *this;
+      }
+
+      ////////////////////////////////////////////////////////////
+      //
+      // Input Binary Operators
+      //
+      ////////////////////////////////////////////////////////////
+      biniostream& operator>> (char& c) {
+        read((char*)&c, sizeof(char));
+        return *this;
+      }
+
+      biniostream& operator>> (unsigned char& c) {
+        read((char*)&c, sizeof(unsigned char));
+        return *this;
+      }
+
+      biniostream& operator>> (signed char& c) {
+        read((char*)&c, sizeof(signed char));
+        return *this;
+      }
+
+      biniostream& operator>> (int& i) {
+        read((char*)&i, sizeof(int));
+        i = intohl((unsigned int)i);
+        return *this;
+      }
+
+      biniostream& operator>> (unsigned int& i) {
+        read((char*)&i, sizeof(unsigned int));
+        i = intohl(i);
+        return *this;
+      }
+
+      biniostream& operator>> (short& s) {
+        read((char*)&s, sizeof(short));
+        s = intohs((unsigned short)s);
+        return *this;
+      }
+
+      biniostream& operator>> (unsigned short& s) {
+        read((char*)&s, sizeof(unsigned short));
+        s = intohs(s);
+        return *this;
+      }
+
+      biniostream& operator>> (long& l) {
+	l = 0;
+        read((char*)&l, LONGSIZE);
+        l = intohl((unsigned long)l);
+	if (((*((char*)(&l)+3)) & (1 << (7-(0)%8))) && (sizeof(long)-LONGSIZE > 0)) {
+	  (void) memset((char *)&l+4, 255, sizeof(long)-LONGSIZE);
+	}
+        return *this;
+      }
+
+      biniostream& operator>> (unsigned long& l) {
+	l = 0;
+        read((char*)&l, LONGSIZE);
+        l = intohl(l);
+	return *this;
+      }
+
+      biniostream& operator>> (char* cp) {
+        int len;
+        read((char*)&len, sizeof(int));
+        read(cp,len);
+        return *this;
+      }
+
+      biniostream& operator>> (bool& b) {
+        read((char*)&b, sizeof(bool));
+        return *this;
+      }
+
+      biniostream& operator>> (float& f) {
+        read((char*)&f, sizeof(float));
+        return *this;
+      }
+
+      biniostream& operator>> (double& d) {
+        read((char*)&d, sizeof(double));
+        return *this;
+      }
+
+      biniostream& operator>> (long double& d) {
+        read((char*)&d, sizeof(long double));
+        return *this;
+      }
+
+      biniostream& operator>> (u_signed64& d) {
+        //read((char*)&d, sizeof(u_signed64));
+        unsigned int n;
+        read((char*)&n, LONGSIZE);
+        d = intohl((unsigned int)n);     // Least Significant part first
+        read((char*)&n, LONGSIZE);
+        n = intohl((unsigned int)n);
+        d += (u_signed64)n << 32; 
+        return *this;
+      }
+      
+      biniostream& operator>> (signed64& d) {
+        //read((char*)&d, sizeof(signed64));
+        unsigned int n;
+        read((char*)&n, LONGSIZE);
+        d = intohl((unsigned int)n);     // Least Significant part first
+        read((char*)&n, LONGSIZE);
+        n = intohl((unsigned int)n);
+        d += (u_signed64)n << 32; 
+        return *this;
+      }
+      
+    };
+
+  } // end of namespace io
+
+} // end of namespace castor
+
+
+template <class charT, class traits, class Allocator>
+  castor::io::biniostream&
+  operator>> (castor::io::biniostream& os,
+              std::basic_string <charT, traits, Allocator>& s) {
+  s.erase();
+  int len;
+  os >> len;
+  char* buf = (char*)malloc(len+1);
+  if(0 == buf) {
+    castor::exception::OutOfMemory e;
+    e.getMessage() << "Failed to allocate buffer of length " << len;
+    throw e;
+  }
+  os.read(buf, len);
+  buf[len] = 0;
+  s += buf;
+  free(buf);
+  return os;
+}
+
+template <class charT, class traits, class Allocator>
+  castor::io::biniostream &
+  operator<< (castor::io::biniostream& os,
+              const std::basic_string <charT, traits, Allocator>& s) {
+  int len = s.length();
+  os << len;
+  os.write(s.data(), len);
+  return os;
+}
+
+
diff --git a/tapeserver/castor/io/io.cpp b/tapeserver/castor/io/io.cpp
index c98fee5f14f5d38f2f1ac75e55bbd982abb6d580..e2eaba8fe66347a25907c65f9f31fa56ca2a141f 100644
--- a/tapeserver/castor/io/io.cpp
+++ b/tapeserver/castor/io/io.cpp
@@ -27,8 +27,9 @@
 #include "castor/io/io.hpp"
 #include "castor/utils/SmartFd.hpp"
 #include "castor/utils/utils.hpp"
-#include "serrno.h"
-#include "net.h"
+#include "common/Utils.hpp"
+#include "common/Timer.hpp"
+#include "common/exception/Errnum.hpp"
 
 #include <arpa/inet.h>
 #include <fcntl.h>
@@ -38,6 +39,7 @@
 #include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <sys/poll.h>
 #include <time.h>
 #include <list>
 
@@ -129,10 +131,9 @@ int castor::io::createListenerSock(
   // Create a socket
   utils::SmartFd sock(socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
   if(sock.get() < 0) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
-    ex.getMessage() << ": Failed to create socket: " << errBuf;
+    ex.getMessage() << ": Failed to create socket: " 
+      << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
@@ -141,8 +142,6 @@ int castor::io::createListenerSock(
     int reuseaddrOptval = 1;
     if(0 > setsockopt(sock.get(), SOL_SOCKET, SO_REUSEADDR,
       (char *)&reuseaddrOptval, sizeof(reuseaddrOptval))) {
-      char errBuf[100];
-      sstrerror_r(errno, errBuf, sizeof(errBuf));
       castor::exception::Exception ex;
       ex.getMessage() <<
         ": Failed to set socket option"
@@ -150,7 +149,7 @@ int castor::io::createListenerSock(
         " level=SOL_SOCKET"
         " optname=SO_REUSEADDR"
         " optval=" << reuseaddrOptval <<
-        ": " << errBuf;
+        ": " << cta::Utils::errnoToString(errno);
       throw ex;
     }
   }
@@ -179,13 +178,11 @@ int castor::io::createListenerSock(
 
       // Mark the socket as being a listener
       if(listen(sock.get(), LISTENBACKLOG) < 0) {
-        char errBuf[100];
-        sstrerror_r(errno, errBuf, sizeof(errBuf));
         castor::exception::Exception ex;
         ex.getMessage() <<
           ": Failed to mark socket as being a listener"
           ": listenSocketFd=" << sock.get() <<
-          ": " << errBuf;
+          ": " << cta::Utils::errnoToString(errno);
         throw ex;
       }
 
@@ -201,13 +198,11 @@ int castor::io::createListenerSock(
 
       // Else throw an exception
       } else {
-        char errBuf[100];
-        sstrerror_r(bindErrno, errBuf, sizeof(errBuf));
         castor::exception::Exception ex;
         ex.getMessage() <<
           ": Failed to bind listener socket"
           ": listenSocketFd=" << sock.get() <<
-          ": " << errBuf;
+          ": " << cta::Utils::errnoToString(bindErrno);
         throw ex;
       }
     }
@@ -280,9 +275,7 @@ int castor::io::acceptConnection(const int listenSocketFd)
     if(savedErrno == EINVAL) {
       reason << ": Socket is not listening for connections";
     } else {
-      char errBuf[100];
-      sstrerror_r(savedErrno, errBuf, sizeof(errBuf));
-      reason << ": " << errBuf;
+      reason << ": " << cta::Utils::errnoToString(savedErrno);
     }
 
     castor::exception::Exception ex;
@@ -344,11 +337,9 @@ int castor::io::acceptConnection(const int listenSocketFd,
 
       throw ex;
     } else {
-      char errBuf[100];
-      sstrerror_r(selectErrno, errBuf, sizeof(errBuf));
       castor::exception::Exception ex;
       ex.getMessage() << "Failed to accept connection: Select failed: " <<
-        errBuf;
+        cta::Utils::errnoToString(selectErrno);
       throw ex;
     }
     break;
@@ -379,9 +370,7 @@ int castor::io::acceptConnection(const int listenSocketFd,
     if(acceptErrno == EINVAL) {
       reason << ": Socket is not listening for connections";
     } else {
-      char errBuf[100];
-      sstrerror_r(acceptErrno, errBuf, sizeof(errBuf));
-      reason << ": " << errBuf;
+      reason << ": " << cta::Utils::errnoToString(acceptErrno);
     }
 
     castor::exception::Exception ex;
@@ -412,11 +401,9 @@ castor::io::IpAndPort castor::io::getSockIpPort(
   socklen_t addressLen = sizeof(address);
 
   if(getsockname(socketFd, (struct sockaddr*)&address, &addressLen) < 0) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
     ex.getMessage() << "Failed to get socket name: socketFd=" << socketFd <<
-      ": " << errBuf;
+      ": " << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
@@ -443,11 +430,9 @@ castor::io::IpAndPort  castor::io::getPeerIpPort(
   socklen_t addressLen = sizeof(address);
 
   if(getpeername(socketFd, (struct sockaddr*)&address, &addressLen) < 0) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
     ex.getMessage() << ": Failed to get peer name: socketFd=" << socketFd <<
-      ": " << errBuf;
+      ": " << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
@@ -472,11 +457,9 @@ std::string castor::io::getSockHostName(const int socketFd) {
   socklen_t addressLen = sizeof(address);
 
   if(getsockname(socketFd, (struct sockaddr*)&address, &addressLen) < 0) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
     ex.getMessage() << "Failed to get socket hostname"
-      ": socketFd=" << socketFd << ": " << errBuf;
+      ": socketFd=" << socketFd << ": " << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
@@ -486,7 +469,7 @@ std::string castor::io::getSockHostName(const int socketFd) {
     hostName, sizeof(hostName), serviceName, sizeof(serviceName), 0);
 
   if(error != 0) {
-    castor::exception::Exception ex(SENOSHOST);
+    castor::exception::Exception ex;
     ex.getMessage() <<
       ": Failed to get host information by address"
       ": socketFd=" << socketFd <<
@@ -521,13 +504,11 @@ void castor::io::getSockIpHostnamePort(
   socklen_t addressLen = sizeof(address);
 
   if(getsockname(socketFd, (struct sockaddr*)&address, &addressLen) < 0) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
     ex.getMessage() <<
       ": Failed to get socket name"
       ": socketFd=" << socketFd <<
-      ": " << errBuf;
+      ": " << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
@@ -540,7 +521,7 @@ void castor::io::getSockIpHostnamePort(
       hostName, hostNameLen, serviceName, sizeof(serviceName), 0);
 
     if(rc != 0) {
-      castor::exception::Exception ex(SENOSHOST);
+      castor::exception::Exception ex;
       ex.getMessage() <<
         ": Failed to get host information by address"
         ": socketFd=" << socketFd <<
@@ -567,13 +548,11 @@ std::string castor::io::getPeerHostName(const int socketFd) {
   socklen_t addressLen = sizeof(address);
 
   if(getpeername(socketFd, (struct sockaddr*)&address, &addressLen) < 0) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
     ex.getMessage() <<
       ": Failed to get peer name"
       ": socketFd=" << socketFd <<
-      ": " << errBuf;
+      ": " << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
@@ -584,7 +563,7 @@ std::string castor::io::getPeerHostName(const int socketFd) {
       hostName, sizeof(hostName), serviceName, sizeof(serviceName), 0);
 
     if(rc != 0) {
-      castor::exception::Exception ex(SENOSHOST);
+      castor::exception::Exception ex;
       ex.getMessage() <<
         ": Failed to get host information by address"
         ": socketFd=" << socketFd <<
@@ -658,103 +637,56 @@ void castor::io::readBytes(
   const int   socketFd,
   const int   timeout,
   const int   nbBytes,
-  char *const buf)
-   {
-
+  char *const buf) {
   // Throw an exception if socketFd is invalid
   if(socketFd < 0) {
     castor::exception::InvalidArgument ex;
     ex.getMessage() <<
-      "Invalid socket file-descriptor"
+      "In io::readBytes: Invalid socket file-descriptor"
       ": socketFd=" << socketFd;
     throw ex;
   }
 
-  const bool connClosed = readBytesFromCloseable(socketFd, timeout, nbBytes,
-    buf);
-
-  if(connClosed) {
-    std::stringstream oss;
-    oss << "Failed to read " << nbBytes << " bytes from socket: ";
-    writeSockDescription(oss, socketFd);
-    oss << ": Connection was closed by the remote end";
-
-    castor::exception::Exception ex(SECONNDROP);
-    ex.getMessage() << oss.str();
-    throw ex;
-  }
-}
-
-//------------------------------------------------------------------------------
-// readBytesFromCloseable
-//------------------------------------------------------------------------------
-bool castor::io::readBytesFromCloseable(
-  const int   socketFd,
-  const int   timeout,
-  const int   nbBytes,
-  char *const buf) {
-
-  // Throw an exception if socketFd is invalid
-  if(socketFd < 0) {
+  if (timeout < 0) {
     castor::exception::InvalidArgument ex;
     ex.getMessage() <<
-      "Invalid socket file-descriptor"
-      ": socketFd=" << socketFd;
+      "In io::readBytes: Invalid timeout value: " << timeout;
     throw ex;
   }
-
-  bool connClosed = false;
-  const int rc = netread_timeout(socketFd, buf, nbBytes, timeout);
-  int savedSerrno = serrno;
-
-  switch(rc) {
-  case -1:
+  
+  cta::utils::Timer timer;
+  size_t bytesRemaining = nbBytes;
+  char * readPtr = buf;
+  while (bytesRemaining > 0) {
     {
-      std::stringstream oss;
-      oss << "Failed to read " << nbBytes << " bytes from socket: " <<
-        " socketFd=" << socketFd << ": ";
-      writeSockDescription(oss, socketFd);
-      // netread_timeout can return -1 with serrno set to 0
-      if(0 == savedSerrno) {
-        savedSerrno = SEINTERNAL;
-        oss << ": Unknown error";
-      } else {
-        char errBuf[100];
-        sstrerror_r(savedSerrno, errBuf, sizeof(errBuf));
-        oss << ": " << errBuf;
+      struct ::pollfd pollDescr;
+      pollDescr.fd = socketFd;
+      pollDescr.events = POLLIN;
+      pollDescr.revents = 0;
+      int pollRet = poll(&pollDescr, 1, (timeout * 1000) - (timer.usecs()/1000));
+      cta::exception::Errnum::throwOnMinusOne(pollRet, "In io::readBytes: failed to poll socket");
+      if (!pollRet) 
+        throw cta::exception::Exception("In io::readBytes: timeout");
+      if (pollRet != 1) {
+        std::stringstream err;
+        err << "In io::readBytes: unexpected return value from poll: " << pollRet;
+        throw cta::exception::Exception(err.str());
       }
-      if(SETIMEDOUT == savedSerrno) {
-        oss << ": timeout=" << timeout;
-      }
-
-      castor::exception::Exception ex(savedSerrno);
-      ex.getMessage() << oss.str();
-      throw ex;
     }
-    break;
-  case 0:
     {
-      connClosed = true;
-    }
-    break;
-  default:
-    if (rc != nbBytes) {
-
-      std::stringstream oss;
-      oss << "Failed to read " << nbBytes << " bytes from socket: ";
-      writeSockDescription(oss, socketFd);
-      oss
-        << ": Read the wrong number of bytes"
-        << ": Expected: " << nbBytes
-        << ": Read: " << rc;
-
-      castor::exception::Exception ex(SECOMERR);
-      ex.getMessage() << oss.str();
-      throw ex;
+      int recvRet = recv(socketFd, readPtr, bytesRemaining, 0);
+      cta::exception::Errnum::throwOnMinusOne(recvRet, "In io::readBytes: failed to receive data: ");
+      if (recvRet > 0) {
+        // We did read more data...
+        readPtr += recvRet;
+        bytesRemaining -= recvRet;
+      } else {
+        std::stringstream err;
+        err << "In io::readBytes: unexpected return value from recv: " << recvRet;
+        throw cta::exception::Exception(err.str());
+      }
     }
   }
-
-  return connClosed;
 }
 
 //------------------------------------------------------------------------------
@@ -765,67 +697,55 @@ void castor::io::writeBytes(
   const int   timeout,
   const int   nbBytes,
   char *const buf)
-   {
+{
 
   // Throw an exception if socketFd is invalid
   if(socketFd < 0) {
     castor::exception::InvalidArgument ex;
     ex.getMessage() <<
-      "Invalid socket file-descriptor"
+      "In io::writeBytes: Invalid socket file-descriptor"
       ": socketFd=" << socketFd;
     throw ex;
   }
-
-  const int rc = netwrite_timeout(socketFd, buf, nbBytes, timeout);
-  int savedSerrno = serrno;
-
-  switch(rc) {
-  case -1:
+  
+  if (timeout < 0) {
+    castor::exception::InvalidArgument ex;
+    ex.getMessage() <<
+      "In io::writeBytes: Invalid timeout value: " << timeout;
+    throw ex;
+  }
+  
+  cta::utils::Timer timer;
+  size_t bytesRemaining = nbBytes;
+  char * writePtr = buf;
+  while (bytesRemaining > 0) {
     {
-      std::stringstream oss;
-      oss << "Failed to write " << nbBytes << " bytes to socket: " <<
-        " socketFd=" << socketFd << ": ";
-      writeSockDescription(oss, socketFd);
-      // netwrite_timeout can return -1 with serrno set to 0
-      if(0 == savedSerrno) {
-        savedSerrno = SEINTERNAL;
-        oss << ": Unknown error";
-      } else {
-        char errBuf[100];
-        sstrerror_r(savedSerrno, errBuf, sizeof(errBuf));
-        oss << ": " << errBuf;
-      }
-      if(savedSerrno == SETIMEDOUT) {
-        oss << ": timeout=" << timeout;
+      struct ::pollfd pollDescr;
+      pollDescr.fd = socketFd;
+      pollDescr.events = POLLOUT;
+      pollDescr.revents = 0;
+      int pollRet = poll(&pollDescr, 1, (timeout * 1000) - (timer.usecs()/1000));
+      cta::exception::Errnum::throwOnMinusOne(pollRet, "In io::writeBytes: failed to poll socket");
+      if (!pollRet) 
+        throw cta::exception::Exception("In io::writeBytes: timeout");
+      if (pollRet != 1) {
+        std::stringstream err;
+        err << "In io::writeBytes: unexpected return value from poll: " << pollRet;
+        throw cta::exception::Exception(err.str());
       }
-
-      castor::exception::Exception ex(SECOMERR);
-      ex.getMessage() << oss.str();
-      throw ex;
     }
-  case 0:
     {
-      std::stringstream oss;
-      oss << "Failed to write " << nbBytes << " bytes to socket: ";
-      writeSockDescription(oss, socketFd);
-      oss << ": Connection dropped";
-
-      castor::exception::Exception ex(SECONNDROP);
-      ex.getMessage() << oss.str();
-      throw ex;
-    }
-  default:
-    if(rc != nbBytes) {
-      std::stringstream oss;
-      oss << "Failed to write " << nbBytes << " bytes to socket: ";
-      writeSockDescription(oss, socketFd);
-      oss
-        << ": Wrote the wrong number of bytes"
-        << ": Expected: " << nbBytes
-        << ": Wrote: " << rc;
-      castor::exception::Exception ex(SECOMERR);
-      ex.getMessage() << oss.str();
-      throw ex;
+      int sendRet = recv(socketFd, writePtr, bytesRemaining, 0);
+      cta::exception::Errnum::throwOnMinusOne(sendRet, "In io::writeBytes: failed to send data: ");
+      if (sendRet > 0) {
+        // We did read more data...
+        writePtr += sendRet;
+        bytesRemaining -= sendRet;
+      } else {
+        std::stringstream err;
+        err << "In io::writeBytes: unexpected return value from send: " << sendRet;
+        throw cta::exception::Exception(err.str());
+      }
     }
   }
 }
@@ -956,36 +876,30 @@ int castor::io::connectWithTimeout(
   // Create the socket for the new connection
   utils::SmartFd smartSock(socket(sockDomain, sockType, sockProtocol));
   if(-1 == smartSock.get()) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
     ex.getMessage() <<
       "Failed to create socket for new connection"
-      ": Call to socket() failed: " << errBuf;
+      ": Call to socket() failed: " << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
   // Get the orginal file-control flags of the socket
   const int orginalFileControlFlags = fcntl(smartSock.get(), F_GETFL, 0);
   if(-1 == orginalFileControlFlags) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
     ex.getMessage() <<
       "Failed to get the original file-control flags of the socket"
-      ": Call to fcntl() failed: " << errBuf;
+      ": Call to fcntl() failed: " << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
   // Set the O_NONBLOCK file-control flag of the socket
   if(-1 == fcntl(smartSock.get(), F_SETFL,
     orginalFileControlFlags | O_NONBLOCK)) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
     ex.getMessage() <<
       "Failed to set the O_NONBLOCK file-control flag"
-      ": Call to fcntl() failed: " << errBuf;
+      ": Call to fcntl() failed: " << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
@@ -997,12 +911,10 @@ int castor::io::connectWithTimeout(
   // file-control flags of the socket and return it
   if(0 == connectRc) {
     if(-1 == fcntl(smartSock.get(), F_SETFL, orginalFileControlFlags)) {
-      char errBuf[100];
-      sstrerror_r(errno, errBuf, sizeof(errBuf));
       castor::exception::Exception ex;
       ex.getMessage() <<
         "Failed to restore the file-control flags of the socket"
-        ": " << errBuf;
+        ": " << cta::Utils::errnoToString(errno);
       throw ex;
     }
     return smartSock.release();
@@ -1011,10 +923,9 @@ int castor::io::connectWithTimeout(
   // Throw an exception if there was any other error than
   // "operation in progress" when trying to start to connect
   if(EINPROGRESS != connectErrno) {
-    char errBuf[100];
-    sstrerror_r(connectErrno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
-    ex.getMessage() << "Call to connect() failed: " << errBuf;
+    ex.getMessage() << "Call to connect() failed: " 
+      << cta::Utils::errnoToString(connectErrno);
     throw ex;
   }
 
@@ -1032,10 +943,9 @@ int castor::io::connectWithTimeout(
   const int selectRc = select(smartSock.get() + 1, &readFds, &writeFds, NULL,
     &selectTimeout);
   if(-1 == selectRc) {
-    char errBuf[100];
-    sstrerror_r(errno, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
-    ex.getMessage() << "Call to select() failed: " << errBuf;
+    ex.getMessage() << "Call to select() failed: "
+      << cta::Utils::errnoToString(errno);
     throw ex;
   }
 
@@ -1052,8 +962,7 @@ int castor::io::connectWithTimeout(
   if(!FD_ISSET(smartSock.get(), &readFds) &&
     !FD_ISSET(smartSock.get(), &writeFds)) {
     castor::exception::Exception ex(ECANCELED);
-    ex.getMessage() <<
-      "Failed to connect"
+    ex.getMessage() << "Failed to connect"
       ": select() returned with no timneout or any descriptors set";
     throw ex;
   }
@@ -1065,35 +974,22 @@ int castor::io::connectWithTimeout(
   // return -1 and set errno, whereas BSD will return 0 and set sockoptError
   int sockoptError = 0;
   socklen_t sockoptErrorLen = sizeof(sockoptError);
-  const int getsockoptRc = getsockopt(smartSock.get(), SOL_SOCKET, SO_ERROR,
-    &sockoptError, &sockoptErrorLen);
-  const int getsockoptErrno = errno;
-  if(-1 == getsockoptRc) { // Solaris
-    char errBuf[100];
-    sstrerror_r(getsockoptErrno, errBuf, sizeof(errBuf));
-    castor::exception::Exception ex;
-    ex.getMessage() <<
-      "Connection did not complete successfully: " << errBuf;
-    throw ex;
-  }
+  cta::exception::Errnum::throwOnMinusOne(
+    getsockopt(smartSock.get(), SOL_SOCKET, SO_ERROR, &sockoptError, 
+      &sockoptErrorLen), 
+    "In io::connectWithTimeout: failed to getsockopt: ");
   if(0 != sockoptError) { // BSD
-    char errBuf[100];
-    sstrerror_r(sockoptError, errBuf, sizeof(errBuf));
     castor::exception::Exception ex;
-    ex.getMessage() <<
-      "Connection did not complete successfully: " << errBuf;
+    ex.getMessage() 
+      << "In io::connectWithTimeout: Connection did not complete successfully: " 
+      << cta::Utils::errnoToString(sockoptError);
     throw ex;
   }
 
   // Restore the original file-control flags of the socket
-  if(-1 == fcntl(smartSock.get(), F_SETFL, orginalFileControlFlags)) {
-    char errBuf[100];
-    sstrerror_r(errno,  errBuf, sizeof(errBuf));
-    castor::exception::Exception ex;
-    ex.getMessage() <<
-      "Failed to restore the file-control flags of the socket: " << errBuf;
-    throw ex;
-  }
+  cta::exception::Errnum::throwOnMinusOne(
+    fcntl(smartSock.get(), F_SETFL, orginalFileControlFlags),
+    "In io::connectWithTimeout: failed to restore flags with fcntl: ");
 
   return smartSock.release();
 }
diff --git a/tapeserver/castor/io/io.hpp b/tapeserver/castor/io/io.hpp
index 1afa03513078ec64939c18e24b267965b159ea19..89621d5dc27b1b1416fb92e0fe8dd7b031b011d7 100644
--- a/tapeserver/castor/io/io.hpp
+++ b/tapeserver/castor/io/io.hpp
@@ -324,25 +324,7 @@ void readBytes(
   const int   socketFd,
   const int   timeout,
   const int   nbBytes,
-  char *const buf)
-  ;
-
-/**
- * Reads the specified number of bytes from the specified closable socket
- * and writes the result into the specified buffer.
- *
- * @param socketFd   The file descriptor of the socket to be read from.
- * @param timeout    The timeout in seconds.
- * @param nbBytes    The number of bytes to be read.
- * @param buf        The buffer into which the bytes will be written.
- * @return           True if the connection was closed by the peer, else false.
- */
-bool readBytesFromCloseable(
-  const int   socketFd, 
-  const int   timeout,
-  const int   nbBytes,
-  char *const buf) 
-  ;
+  char *const buf);
 
 /**
  * Writes the specified number of bytes from the specified buffer to the
diff --git a/tapeserver/castor/legacymsg/CMakeLists.txt b/tapeserver/castor/legacymsg/CMakeLists.txt
index 6a9aa901344497e497d5ec0d898fa7a2c06687b2..4d96f0ad85e863f8b1b9212a616f96636e7c57d3 100644
--- a/tapeserver/castor/legacymsg/CMakeLists.txt
+++ b/tapeserver/castor/legacymsg/CMakeLists.txt
@@ -3,11 +3,17 @@ cmake_minimum_required (VERSION 2.6)
 include_directories(${PROJECT_SOURCE_DIR}/tapeserver)
 include_directories(${PROJECT_SOURCE_DIR}/tapeserver/h)
 
+add_library (ctalegacymsg
+  TapeLabelRqstMsgBody.cpp
+  RmcProxyTcpIp.cpp
+  RmcMarshal.cpp
+  GenericMarshal.cpp
+  MessageHeader.cpp)
+
 add_library (ctalegacymsgunittests SHARED
   CommonMarshalTest.cpp
   GenericMarshalTest.cpp
   TapeMarshalTest.cpp)
 target_link_libraries (ctalegacymsgunittests
   castorclient
-  castorlegacymsg
   ctamessages)
diff --git a/tapeserver/castor/legacymsg/GenericMarshal.cpp b/tapeserver/castor/legacymsg/GenericMarshal.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ca6e1e7e4ca2bccec82c85252c311c1a2a123458
--- /dev/null
+++ b/tapeserver/castor/legacymsg/GenericMarshal.cpp
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * 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 "castor/io/io.hpp"
+#include "castor/legacymsg/GenericMarshal.hpp"
+
+#include <string.h>
+
+//-----------------------------------------------------------------------------
+// marshal
+//-----------------------------------------------------------------------------
+size_t castor::legacymsg::marshal(char *const dst, const size_t dstLen,
+  const uint32_t srcMagic, const uint32_t srcReqType,
+  const GenericReplyMsgBody &srcBody)  {
+  const char *const task = "marshal GenericReplyMsgBody";
+
+  if(dst == NULL) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": Pointer to destination buffer is NULL";
+    throw ex;
+  }
+
+  // Calculate the length of the message body
+  const uint32_t bodyLen =
+    sizeof(srcBody.status) +
+    strlen(srcBody.errorMessage) + 1;
+
+  // Calculate the total length of the message (header + body)
+  const uint32_t totalLen =
+    sizeof(uint32_t) + // magic
+    sizeof(uint32_t) + // reqType
+    sizeof(uint32_t) + // len
+    bodyLen;
+
+  // Check that the message buffer is big enough
+  if(totalLen > dstLen) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": Buffer too small: required=" << totalLen << " actual=" << dstLen;
+    throw ex;
+  }
+
+  // Marshal message header
+  char *p = dst;
+  try {
+    io::marshalUint32(srcMagic, p);
+    io::marshalUint32(srcReqType, p);
+    io::marshalUint32(bodyLen, p);
+  } catch(castor::exception::Exception &ne) { 
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task << ": Failed to marshal header: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  // Marshal message body
+  try {
+    io::marshalUint32(srcBody.status, p);
+    io::marshalString(srcBody.errorMessage, p);
+  } catch(castor::exception::Exception &ne) { 
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task << ": Failed to marshal body: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  // 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) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": 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,
+  GenericReplyMsgBody &dst)  {
+  try {
+    io::unmarshalUint32(src, srcLen, dst.status);
+    io::unmarshalString(src, srcLen, dst.errorMessage);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to unmarshal GenericReplyMsgBody: " <<
+      ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// marshal
+//-----------------------------------------------------------------------------
+size_t castor::legacymsg::marshal(char *const dst, const size_t dstLen,
+  const uint32_t srcMagic, const uint32_t srcReqType,
+  const GenericErrorReplyMsgBody &srcBody)  {
+  const char *const task = "marshal GenericErrorReplyMsgBody";
+
+  if(dst == NULL) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": Pointer to destination buffer is NULL";
+    throw ex;
+  }
+
+  // Calculate the length of the message body
+  const uint32_t bodyLen = strlen(srcBody.errorMessage) + 1;
+
+  // Calculate the total length of the message (header + body)
+  const uint32_t totalLen =
+    sizeof(uint32_t) + // magic
+    sizeof(uint32_t) + // reqType
+    sizeof(uint32_t) + // len
+    bodyLen;
+
+  // Check that the message buffer is big enough
+  if(totalLen > dstLen) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": Buffer too small: required=" << totalLen << " actual=" << dstLen;
+    throw ex;
+  }
+
+  // Marshal message header
+  char *p = dst;
+  try {
+    io::marshalUint32(srcMagic, p);
+    io::marshalUint32(srcReqType, p);
+    io::marshalUint32(bodyLen, p);
+  } catch(castor::exception::Exception &ne) { 
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task << ": Failed to marshal header: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  // Marshal message body
+  try {
+    io::marshalString(srcBody.errorMessage, p);
+  } catch(castor::exception::Exception &ne) { 
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task << ": Failed to marshal body: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  // 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) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": 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,
+  GenericErrorReplyMsgBody &dst)  {
+  try {
+    io::unmarshalString(src, srcLen, dst.errorMessage);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to unmarshal GenericErrorReplyMsgBody: " <<
+      ne.getMessage().str();
+    throw ex;
+  }
+}
diff --git a/tapeserver/castor/legacymsg/GenericMarshal_1.hpp b/tapeserver/castor/legacymsg/GenericMarshal_1.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c8ca2369927920930b798626a22519e54e4dbb86
--- /dev/null
+++ b/tapeserver/castor/legacymsg/GenericMarshal_1.hpp
@@ -0,0 +1,139 @@
+/******************************************************************************
+ *
+ * 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 "castor/exception/Exception.hpp"
+#include "castor/legacymsg/GenericReplyMsgBody.hpp"
+#include "castor/legacymsg/GenericErrorReplyMsgBody.hpp"
+
+#include <stdint.h>
+
+namespace castor {
+namespace legacymsg {
+
+/**
+ * Marshals the specified source message into the specified destination buffer.
+ *
+ * Please note that this method marshals the length of the message body as the
+ * third field of the message header (message header = magic + reqType + len).
+ *
+ * @param dst        The destination message buffer.
+ * @param dstLen     The length of the destination buffer.
+ * @param srcMagic   The magic number of the source message.
+ * @param srcReqType The request type of the source message.
+ * @param srcBody    The body of the source message.
+ *
+ * @return         The total length of the message (header + body).
+ */
+size_t marshal(char *const dst, const size_t dstLen, const uint32_t srcMagic,
+  const uint32_t srcReqType, const GenericReplyMsgBody &srcBody)
+  ;
+
+/**
+ * Marshals the specified source message into the specified destination buffer.
+ *
+ * Please note that this method marshals the length of the message body as the
+ * third field of the message header (message header = magic + reqType + len).
+ *
+ * @param dst        The destination message buffer.
+ * @param srcMagic   The magic number of the source message.
+ * @param srcReqType The request type of the source message.
+ * @param srcBody    The body of the source message.
+ * @return           The total length of the message (header + body).
+ */
+template<int n> size_t marshal(char (&dst)[n], const uint32_t srcMagic,
+  const uint32_t srcReqType, const GenericReplyMsgBody &srcBody)
+   {
+  return marshal(dst, n, srcMagic, srcReqType, srcBody);
+}
+
+/**
+ * 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/out 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, GenericReplyMsgBody &dst) ;
+
+/**
+ * Marshals the specified source message into the specified destination buffer.
+ *
+ * Please note that this method marshals the length of the message body as the
+ * third field of the message header (message header = magic + reqType + len).
+ *
+ * @param dst        The destination message buffer.
+ * @param dstLen     The length of the destination buffer.
+ * @param srcMagic   The magic number of the source message.
+ * @param srcReqType The request type of the source message.
+ * @param srcBody    The body of the source message.
+ *
+ * @return         The total length of the message (header + body).
+ */
+size_t marshal(char *const dst, const size_t dstLen, const uint32_t srcMagic,
+  const uint32_t srcReqType, const GenericErrorReplyMsgBody &srcBody)
+  ;
+
+/**
+ * Marshals the specified source message into the specified destination buffer.
+ *
+ * Please note that this method marshals the length of the message body as the
+ * third field of the message header (message header = magic + reqType + len).
+ *
+ * @param dst        The destination message buffer.
+ * @param srcMagic   The magic number of the source message.
+ * @param srcReqType The request type of the source message.
+ * @param srcBody    The body of the source message.
+ * @return           The total length of the message (header + body).
+ */
+template<int n> size_t marshal(char (&dst)[n], const uint32_t srcMagic,
+  const uint32_t srcReqType, const GenericErrorReplyMsgBody &srcBody)
+   {
+  return marshal(dst, n, srcMagic, srcReqType, srcBody);
+}
+
+/**
+ * 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/out 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, GenericErrorReplyMsgBody &dst) ;
+
+} // namespace legacymsg
+} // namespace castor
diff --git a/tapeserver/castor/legacymsg/MessageHeader.cpp b/tapeserver/castor/legacymsg/MessageHeader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8b0a71364c39e6834eac4e642e2b1b797002306e
--- /dev/null
+++ b/tapeserver/castor/legacymsg/MessageHeader.cpp
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * 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 "castor/legacymsg/MessageHeader.hpp"
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+castor::legacymsg::MessageHeader::MessageHeader() throw():
+  magic(0),
+  reqType(0),
+  lenOrStatus(0) {
+}
diff --git a/tapeserver/castor/legacymsg/RmcMarshal.cpp b/tapeserver/castor/legacymsg/RmcMarshal.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..24447fa9059c7b271a52880d9f15481ef7d854ca
--- /dev/null
+++ b/tapeserver/castor/legacymsg/RmcMarshal.cpp
@@ -0,0 +1,231 @@
+/******************************************************************************
+ *
+ * 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 "castor/io/io.hpp"
+#include "castor/legacymsg/RmcMarshal.hpp"
+#include "rmc_constants.h"
+
+#include <string.h>
+
+//-----------------------------------------------------------------------------
+// marshal
+//-----------------------------------------------------------------------------
+size_t castor::legacymsg::marshal(char *const dst, const size_t dstLen, const RmcMountMsgBody &src)  {
+  const char *task = "marshal RmcMountMsgBody";
+
+  if(dst == NULL) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": Pointer to destination buffer is NULL";
+    throw ex;
+  }
+
+  // Calculate the length of the message body
+  const uint32_t bodyLen =
+    sizeof(src.uid) +
+    sizeof(src.gid) +
+    strlen(src.unusedLoader) + 1 +
+    strlen(src.vid) + 1 +
+    sizeof(src.side) +
+    sizeof(src.drvOrd);
+
+  // Calculate the total length of the message (header + body)
+  const uint32_t totalLen =
+    sizeof(uint32_t) + // magic
+    sizeof(uint32_t) + // reqType
+    sizeof(uint32_t) + // len
+    bodyLen;
+
+  // Check that the message buffer is big enough
+  if(totalLen > dstLen) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": Buffer too small: required=" << totalLen << " actual=" << dstLen;
+    throw ex;
+  }
+
+  // Marshal message header
+  char *p = dst;
+  try {
+    const uint32_t magic = RMC_MAGIC;
+    const uint32_t reqType = RMC_MOUNT;
+    io::marshalUint32(magic , p);
+    io::marshalUint32(reqType, p);
+    io::marshalUint32(totalLen, p);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task << ": Failed to marshal header: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  // Marshal message body
+  try {
+    io::marshalUint32(src.uid, p);
+    io::marshalUint32(src.gid, p);
+    io::marshalString(src.unusedLoader, p);
+    io::marshalString(src.vid, p);
+    io::marshalUint16(src.side, p);
+    io::marshalUint16(src.drvOrd, p);
+  } catch(castor::exception::Exception &ne) { 
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task << ": Failed to marshal body: " 
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  // 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) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": 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, RmcMountMsgBody &dst)  {
+  try {
+    io::unmarshalUint32(src, srcLen, dst.uid);
+    io::unmarshalUint32(src, srcLen, dst.gid);
+    io::unmarshalString(src, srcLen, dst.unusedLoader);
+    io::unmarshalString(src, srcLen, dst.vid);
+    io::unmarshalUint16(src, srcLen, dst.side);
+    io::unmarshalUint16(src, srcLen, dst.drvOrd);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to unmarshal RmcMountMsgBody: " <<
+      ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// marshal
+//-----------------------------------------------------------------------------
+size_t castor::legacymsg::marshal(char *const dst, const size_t dstLen, const RmcUnmountMsgBody &src)  {
+  const char *const task = "marshal RmcUnmountMsgBody";
+
+  if(dst == NULL) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": Pointer to destination buffer is NULL";
+    throw ex;
+  }
+
+  // Calculate the length of the message body
+  const uint32_t bodyLen =
+    sizeof(src.uid) +
+    sizeof(src.gid) +
+    strlen(src.unusedLoader) + 1 +
+    strlen(src.vid) + 1 +
+    sizeof(src.drvOrd) +
+    sizeof(src.force);
+
+  // Calculate the total length of the message (header + body)
+  const uint32_t totalLen =
+    sizeof(uint32_t) + // magic
+    sizeof(uint32_t) + // reqType
+    sizeof(uint32_t) + // len
+    bodyLen;
+
+  // Check that the message buffer is big enough
+  if(totalLen > dstLen) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": Buffer too small: required=" << totalLen << " actual=" << dstLen;
+    throw ex;
+  }
+
+  // Marshal message header
+  char *p = dst;
+  try {
+    const uint32_t magic = RMC_MAGIC;
+    const uint32_t reqType = RMC_UNMOUNT;
+    io::marshalUint32(magic , p);
+    io::marshalUint32(reqType, p);
+    io::marshalUint32(totalLen, p);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task << ": Failed to marshal header: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  // Marshal message body
+  try {
+    io::marshalUint32(src.uid, p);
+    io::marshalUint32(src.gid, p);
+    io::marshalString(src.unusedLoader, p);
+    io::marshalString(src.vid, p);
+    io::marshalUint16(src.drvOrd, p);
+    io::marshalUint16(src.force, p);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task << ": Failed to marshal body: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  // 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) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to " << task <<
+      ": 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, RmcUnmountMsgBody &dst)  {
+  try {
+    io::unmarshalUint32(src, srcLen, dst.uid);
+    io::unmarshalUint32(src, srcLen, dst.gid);
+    io::unmarshalString(src, srcLen, dst.unusedLoader);
+    io::unmarshalString(src, srcLen, dst.vid);
+    io::unmarshalUint16(src, srcLen, dst.drvOrd);
+    io::unmarshalUint16(src, srcLen, dst.force);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to unmarshal RmcUnmountMsgBody: " <<
+      ne.getMessage().str();
+    throw ex;
+  }
+}
diff --git a/tapeserver/castor/legacymsg/RmcMarshal.hpp b/tapeserver/castor/legacymsg/RmcMarshal.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b1742f36a7b151bc9e4e89e1176f5e0c1855328f
--- /dev/null
+++ b/tapeserver/castor/legacymsg/RmcMarshal.hpp
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ * 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 "castor/exception/Exception.hpp"
+#include "castor/legacymsg/RmcMountMsgBody.hpp"
+#include "castor/legacymsg/RmcUnmountMsgBody.hpp"
+
+namespace castor    {
+namespace legacymsg {
+
+/**
+ * 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 RmcMountMsgBody &src) ;
+
+/**
+ * Marshals the specified source message body structure and its implicit
+ * header into the specified destination buffer.
+ *
+ * @param dst The destination message buffer.
+ * @param src The source structure.
+ * @return    The total length of the message (header + body).
+ */
+template<int n> size_t marshal(char (&dst)[n], const RmcMountMsgBody &src)  {
+  return marshal(dst, n, src);
+}
+
+/**
+ * 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/out 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, RmcMountMsgBody &dst) ;
+
+/**
+ * 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 RmcUnmountMsgBody &src) ;
+
+/**
+ * Marshals the specified source message body structure and its implicit
+ * header into the specified destination buffer.
+ *
+ * @param dst The destination message buffer.
+ * @param src The source structure.
+ * @return    The total length of the message (header + body).
+ */
+template<int n> size_t marshal(char (&dst)[n], const RmcUnmountMsgBody &src)  {
+  return marshal(dst, n, src);
+}
+
+/**
+ * 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/out 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, RmcUnmountMsgBody &dst) ;
+
+} // namespace legacymsg
+} // namespace castor
+
diff --git a/tapeserver/castor/legacymsg/RmcProxyTcpIp.cpp b/tapeserver/castor/legacymsg/RmcProxyTcpIp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ffcf8743c15a4273b85cd40b24ef2a44fa77db41
--- /dev/null
+++ b/tapeserver/castor/legacymsg/RmcProxyTcpIp.cpp
@@ -0,0 +1,234 @@
+/******************************************************************************
+ *
+ * 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 "castor/io/io.hpp"
+#include "castor/legacymsg/CommonMarshal.hpp"
+#include "castor/legacymsg/RmcMarshal.hpp"
+#include "castor/legacymsg/RmcProxyTcpIp.hpp"
+#include "castor/utils/SmartFd.hpp"
+#include "castor/utils/utils.hpp"
+#include "Castor_limits.h"
+#include "rmc_constants.h"
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+castor::legacymsg::RmcProxyTcpIp::RmcProxyTcpIp(
+  const unsigned short rmcPort,
+  const int netTimeout,
+  const unsigned int maxRqstAttempts) throw():
+  m_rmcPort(rmcPort),
+  m_netTimeout(netTimeout),
+  m_maxRqstAttempts(maxRqstAttempts) {
+} 
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+castor::legacymsg::RmcProxyTcpIp::~RmcProxyTcpIp() throw() {
+}
+
+//------------------------------------------------------------------------------
+// mountTapeReadOnly
+//------------------------------------------------------------------------------
+void castor::legacymsg::RmcProxyTcpIp::mountTapeReadOnly(
+  const std::string &vid, const mediachanger::ScsiLibrarySlot &librarySlot) {
+  // SCSI libraries do not support read-only mounts
+  mountTapeReadWrite(vid, librarySlot);
+}
+
+//------------------------------------------------------------------------------
+// mountTapeReadWrite
+//------------------------------------------------------------------------------
+void castor::legacymsg::RmcProxyTcpIp::mountTapeReadWrite(
+  const std::string &vid, const mediachanger::ScsiLibrarySlot &librarySlot) {
+  try {
+    RmcMountMsgBody rqstBody;
+    rqstBody.uid = geteuid();
+    rqstBody.gid = getegid();
+    castor::utils::copyString(rqstBody.vid, vid);
+    rqstBody.drvOrd = librarySlot.getDrvOrd();
+
+    rmcSendRecvNbAttempts(m_maxRqstAttempts, librarySlot.getRmcHostName(),
+      rqstBody);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to mount tape in SCSI tape-library for read/write access"
+      ": vid=" << vid << " librarySlot=" << librarySlot.str() << ": " <<
+      ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// dismountTape
+//------------------------------------------------------------------------------
+void castor::legacymsg::RmcProxyTcpIp::dismountTape(const std::string &vid,
+  const mediachanger::ScsiLibrarySlot &librarySlot) {
+  try {
+    RmcUnmountMsgBody rqstBody;
+    rqstBody.uid = geteuid();
+    rqstBody.gid = getegid();
+    castor::utils::copyString(rqstBody.vid, vid);
+    rqstBody.drvOrd = librarySlot.getDrvOrd();
+    rqstBody.force = 0;
+
+    rmcSendRecvNbAttempts(m_maxRqstAttempts, librarySlot.getRmcHostName(),
+      rqstBody);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to dismount tape in SCSI tape-library"
+      ": vid=" << vid << " librarySlot=" << librarySlot.str() << ": " <<
+      ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// forceDismountTape
+//------------------------------------------------------------------------------
+void castor::legacymsg::RmcProxyTcpIp::forceDismountTape(const std::string &vid,
+  const mediachanger::ScsiLibrarySlot &librarySlot) {
+  // SCSI libraries do not support forced dismounts
+  dismountTape(vid, librarySlot);
+}
+
+//-----------------------------------------------------------------------------
+// connectToRmc
+//-----------------------------------------------------------------------------
+int castor::legacymsg::RmcProxyTcpIp::connectToRmc(const std::string &rmcHost)
+  const {
+  castor::utils::SmartFd smartConnectSock;
+  try {
+    smartConnectSock.reset(io::connectWithTimeout(rmcHost, m_rmcPort,
+      m_netTimeout));
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to connect to rmcd: rmcHost=" << rmcHost
+      << " rmcPort=" << RMC_PORT << ": " << ne.getMessage().str();
+    throw ex;
+  }
+
+  return smartConnectSock.release();
+}
+
+//-----------------------------------------------------------------------------
+// writeRmcMountMsg
+//-----------------------------------------------------------------------------
+void castor::legacymsg::RmcProxyTcpIp::writeRmcMountMsg(const int fd,
+  const RmcMountMsgBody &body) {
+  char buf[RMC_MSGBUFSIZ];
+  const size_t len = marshal(buf, body);
+
+  try {
+    io::writeBytes(fd, m_netTimeout, len, buf);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to write RMC_SCSI_MOUNT message: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// readRmcMsgHeader
+//-----------------------------------------------------------------------------
+castor::legacymsg::MessageHeader
+  castor::legacymsg::RmcProxyTcpIp::readRmcMsgHeader(const int fd) {
+  char buf[12]; // Magic + type + len
+  MessageHeader header;
+
+  try {
+    io::readBytes(fd, m_netTimeout, sizeof(buf), buf);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to read message header: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+
+  const char *bufPtr = buf;
+  size_t bufLen = sizeof(buf);
+  unmarshal(bufPtr, bufLen, header);
+
+  if(RMC_MAGIC != header.magic) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to read message header: "
+      " Header contains an invalid magic number: expected=0x" << std::hex <<
+      RMC_MAGIC << " actual=0x" << header.magic;
+    throw ex;
+  }
+
+  return header;
+}
+
+//-----------------------------------------------------------------------------
+// writeRmcUnmountMsg
+//-----------------------------------------------------------------------------
+void castor::legacymsg::RmcProxyTcpIp::writeRmcUnmountMsg(const int fd,
+  const RmcUnmountMsgBody &body) {
+  char buf[RMC_MSGBUFSIZ];
+  const size_t len = marshal(buf, body);
+
+  try {
+    io::writeBytes(fd, m_netTimeout, len, buf);
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() << "Failed to write RMC_SCSI_UNMOUNT message: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// rmcReplyTypeToStr
+//-----------------------------------------------------------------------------
+std::string castor::legacymsg::RmcProxyTcpIp::rmcReplyTypeToStr(
+  const int replyType) {
+  std::ostringstream oss;
+  switch(replyType) {
+  case RMC_RC:
+    oss << "RMC_RC";
+    break;
+  case MSG_ERR:
+    oss << "MSG_ERR";
+    break;
+  default:
+    oss << "UNKNOWN(0x" << std::hex << replyType << ")";
+  }
+  return oss.str();
+}
+
+//-----------------------------------------------------------------------------
+// handleMSG_ERR
+//-----------------------------------------------------------------------------
+std::string castor::legacymsg::RmcProxyTcpIp::handleMSG_ERR(
+  const MessageHeader &header,
+  const int fd) {
+  char errorBuf[1024];
+  const int nbBytesToRead = header.lenOrStatus > sizeof(errorBuf) ?
+    sizeof(errorBuf) : header.lenOrStatus;
+  io::readBytes(fd, m_netTimeout, nbBytesToRead, errorBuf);
+  errorBuf[sizeof(errorBuf) - 1] = '\0';
+  return errorBuf;
+}
diff --git a/tapeserver/castor/legacymsg/TapeLabelRqstMsgBody.cpp b/tapeserver/castor/legacymsg/TapeLabelRqstMsgBody.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..abff6146dc47ccc48c739b84a6b92affe946cad9
--- /dev/null
+++ b/tapeserver/castor/legacymsg/TapeLabelRqstMsgBody.cpp
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * 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 "castor/legacymsg/TapeLabelRqstMsgBody.hpp"
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+castor::legacymsg::TapeLabelRqstMsgBody::TapeLabelRqstMsgBody() throw():
+  force(0),
+  uid(0),
+  gid(0) {
+  memset(vid, '\0', sizeof(vid));
+  memset(drive, '\0', sizeof(drive));
+  memset(logicalLibrary, '\0', sizeof(logicalLibrary));
+}
diff --git a/tapeserver/castor/server/CMakeLists.txt b/tapeserver/castor/server/CMakeLists.txt
index 986504a02fb9b9b6c87b0e85196b8383ae696244..bab11e39ff16b88a9354c767357a87279e4ee3bf 100644
--- a/tapeserver/castor/server/CMakeLists.txt
+++ b/tapeserver/castor/server/CMakeLists.txt
@@ -4,7 +4,12 @@ include_directories(${PROJECT_SOURCE_DIR}/tapeserver)
 include_directories(${PROJECT_SOURCE_DIR}/tapeserver/h)
 
 add_library (ctaserverutils SHARED
-  ProcessCapDummy.cpp)
+  ProcessCapDummy.cpp
+  Semaphores.cpp
+  Mutex.cpp
+  Threading.cpp
+  ProcessCap.cpp
+  Daemon.cpp)
 
 add_library (ctaserverunittests SHARED
   AtomicCounterTest.cpp
@@ -15,5 +20,4 @@ add_library (ctaserverunittests SHARED
   ThreadingMTTests.cpp
   ThreadingTests.cpp)
 
-target_link_libraries (ctaserverunittests
-  castorserver)
+target_link_libraries (ctaserverunittests)
diff --git a/tapeserver/castor/server/Daemon.cpp b/tapeserver/castor/server/Daemon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf9857c8c1862539ddfa75fe1d470a042f01dafe
--- /dev/null
+++ b/tapeserver/castor/server/Daemon.cpp
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ *
+ * 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 "castor/dlf/Dlf.hpp"
+#include "castor/exception/Errnum.hpp"
+#include "castor/server/Daemon.hpp"
+#include "castor/server/ThreadNotification.hpp"
+#include "castor/System.hpp"
+#include <getopt.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+castor::server::Daemon::Daemon(std::ostream &stdOut, std::ostream &stdErr,
+  log::Logger &log) throw():
+  m_stdOut(stdOut),
+  m_stdErr(stdErr),
+  m_log(log),
+  m_foreground(false),
+  m_commandLineHasBeenParsed(false) {
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+castor::server::Daemon::~Daemon() throw() {
+}
+
+//------------------------------------------------------------------------------
+// parseCommandLine
+//------------------------------------------------------------------------------
+void castor::server::Daemon::parseCommandLine(int argc,
+  char *argv[])  {
+  struct ::option longopts[4];
+
+  longopts[0].name = "foreground";
+  longopts[0].has_arg = no_argument;
+  longopts[0].flag = NULL;
+  longopts[0].val = 'f';
+
+  longopts[1].name = "config";
+  longopts[1].has_arg = required_argument;
+  longopts[1].flag = NULL;
+  longopts[1].val = 'c';
+
+  longopts[2].name = "help";
+  longopts[2].has_arg = no_argument;
+  longopts[2].flag = NULL;
+  longopts[2].val = 'h';
+
+  longopts[3].name = 0;
+
+  char c;
+  while ((c = getopt_long(argc, argv, "fc:h", longopts, NULL)) != -1) {
+    switch (c) {
+    case 'f':
+      m_foreground = true;
+      break;
+    case 'c':
+      setenv("PATH_CONFIG", optarg, 1);
+      m_stdOut << "Using configuration file " << optarg << std::endl;
+      break;
+    case 'h':
+      help(argv[0]);
+      exit(0);
+      break;
+    default:
+      break;
+    }
+  }
+
+  m_commandLineHasBeenParsed = true;
+}
+
+//------------------------------------------------------------------------------
+// help
+//------------------------------------------------------------------------------
+void castor::server::Daemon::help(const std::string &programName)
+  throw() {
+  m_stdOut << "Usage: " << programName << " [options]\n"
+    "\n"
+    "where options can be:\n"
+    "\n"
+    "\t--foreground            or -f         \tRemain in the Foreground\n"
+    "\t--config <config-file>  or -c         \tConfiguration file\n"
+    "\t--metrics               or -m         \tEnable metrics collection\n"
+    "\t--help                  or -h         \tPrint this help and exit\n"
+    "\n"
+    "Comments to: Castor.Support@cern.ch\n";
+}
+
+//------------------------------------------------------------------------------
+// getServerName
+//------------------------------------------------------------------------------
+const std::string &castor::server::Daemon::getServerName() const throw() {
+  return m_log.getProgramName();
+}
+
+//------------------------------------------------------------------------------
+// getForeground
+//------------------------------------------------------------------------------
+bool castor::server::Daemon::getForeground() const
+   {
+  if(!m_commandLineHasBeenParsed) {
+    castor::exception::CommandLineNotParsed ex;
+    ex.getMessage() <<
+      "Failed to determine whether or not the daemon should run in the"
+      " foreground because the command-line has not yet been parsed";
+    throw ex;
+  }
+
+  return m_foreground;
+}
+
+//-----------------------------------------------------------------------------
+// setCommandLineParsed
+//-----------------------------------------------------------------------------
+void castor::server::Daemon::setCommandLineHasBeenParsed(const bool foreground)
+  throw() {
+  m_foreground = foreground;
+  m_commandLineHasBeenParsed = true;
+}
+
+//-----------------------------------------------------------------------------
+// dlfInit
+//-----------------------------------------------------------------------------
+void castor::server::Daemon::dlfInit(castor::dlf::Message messages[])
+   {
+  castor::dlf::dlf_init((char*)m_log.getProgramName().c_str(), messages);
+  // Add framework specific messages
+  castor::dlf::Message frameworkMessages[] =
+    {{  1, "Error while reading datagrams" },
+     {  2, "Error while accepting connections" },
+     {  3, "Thread pool started" },
+     {  4, "Exception caught in the user thread" },
+     {  5, "Thread run error" },
+     {  6, "NotifierThread exception" },
+     {  8, "Exception caught while initializing the child process" },
+     {  9, "Error while processing an object from the pipe" },
+     { 10, "Uncaught exception in a thread from pool" },
+     { 11, "Uncaught GENERAL exception in a thread from pool" },
+     { 12, "Caught signal - GRACEFUL STOP" },
+     { 14, "Caught signal - CHILD STOPPED" },
+     { 15, "Signal caught but not handled - IMMEDIATE STOP" },
+     { 16, "Exception during wait for signal loop" },
+     { 18, "No idle thread in pool to process request" },
+     { 19, "Error while dispatching to a thread" },
+     { 20, "Spawning a new thread in pool" },
+     { 21, "Terminating a thread in pool" },
+     { 22, "Task processed" },
+     { -1, "" }};
+  castor::dlf::dlf_addMessages(DLF_BASE_FRAMEWORK, frameworkMessages);
+}
+
+//------------------------------------------------------------------------------
+// daemonizeIfNotRunInForeground
+//------------------------------------------------------------------------------
+void castor::server::Daemon::daemonizeIfNotRunInForeground(
+  const bool runAsStagerSuperuser) {
+  // Do nothing if already a daemon
+  if (1 == getppid())  {
+    return;
+  }
+
+  // If the daemon is to be run in the background
+  if (!m_foreground) {
+    m_log.prepareForFork();
+
+    {
+      pid_t pid = 0;
+      castor::exception::Errnum::throwOnNegative(pid = fork(),
+        "Failed to daemonize: Failed to fork");
+      // If we got a good PID, then we can exit the parent process
+      if (0 < pid) {
+        exit(EXIT_SUCCESS);
+      }
+    }
+
+    // We could set our working directory to '/' here with a call to chdir(2).
+    // For the time being we don't and leave it to the initd script to change
+    // to a suitable directory for us!
+
+    // Change the file mode mask
+    umask(0);
+
+    // Run the daemon in a new session
+    castor::exception::Errnum::throwOnNegative(setsid(),
+      "Failed to daemonize: Failed to run daemon is a new session");
+
+    // Redirect standard files to /dev/null
+    castor::exception::Errnum::throwOnNull(
+      freopen("/dev/null", "r", stdin),
+      "Failed to daemonize: Falied to freopen stdin");
+    castor::exception::Errnum::throwOnNull(
+      freopen("/dev/null", "w", stdout),
+      "Failed to daemonize: Failed to freopen stdout");
+    castor::exception::Errnum::throwOnNull(
+      freopen("/dev/null", "w", stderr),
+      "Failed to daemonize: Failed to freopen stderr");
+  } // if (!m_foreground)
+
+  // Change the user of the daemon process to the Castor superuser if requested
+  if (runAsStagerSuperuser) {
+    castor::System::switchToCastorSuperuser();
+  }
+
+  // Ignore SIGPIPE (connection lost with client)
+  // and SIGXFSZ (a file is too big)
+  signal(SIGPIPE, SIG_IGN);
+  signal(SIGXFSZ, SIG_IGN);
+}
+
diff --git a/tapeserver/castor/server/Daemon.hpp b/tapeserver/castor/server/Daemon.hpp
index 3eeb2eb93252617dc3a698b5702ccd6c82206269..3a953e4ec92b1b8fc538a07a014da6fad8376dd2 100644
--- a/tapeserver/castor/server/Daemon.hpp
+++ b/tapeserver/castor/server/Daemon.hpp
@@ -113,17 +113,6 @@ protected:
    */
   void daemonizeIfNotRunInForeground(const bool runAsStagerSuperuser);
 
-  /**
-   * Sends a notification message to the given host,port
-   * to wake up nbThreads threads to handle pending requests.
-   * @param host the destination host
-   * @param port the destination port
-   * @param tpName the name of the thread pool to be signaled
-   * @param nbThreads the number of threads to be signaled
-   */
-  static void sendNotification(const std::string &host, const int port,
-    const char tpName, const int nbThreads = 1) throw();
-
   /**
    * Stream representing standard out.
    */
diff --git a/tapeserver/castor/server/Mutex.cpp b/tapeserver/castor/server/Mutex.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad034c727fd0237677c72139484515a444089076
--- /dev/null
+++ b/tapeserver/castor/server/Mutex.cpp
@@ -0,0 +1,49 @@
+#include "castor/server/Mutex.hpp"
+#include "castor/exception/Errnum.hpp"
+#include "castor/exception/Exception.hpp"
+
+//------------------------------------------------------------------------------
+//constructor
+//------------------------------------------------------------------------------
+castor::server::Mutex::Mutex()  {
+  pthread_mutexattr_t attr;
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutexattr_init(&attr),
+    "Error from pthread_mutexattr_init in castor::server::Mutex::Mutex()");
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK),
+    "Error from pthread_mutexattr_settype in castor::server::Mutex::Mutex()");
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutex_init(&m_mutex, &attr),
+    "Error from pthread_mutex_init in castor::server::Mutex::Mutex()");
+  try {
+    castor::exception::Errnum::throwOnReturnedErrno(
+      pthread_mutexattr_destroy(&attr),
+      "Error from pthread_mutexattr_destroy in castor::server::Mutex::Mutex()");
+  } catch (...) {
+    pthread_mutex_destroy(&m_mutex);
+    throw;
+  }
+}
+//------------------------------------------------------------------------------
+//destructor
+//------------------------------------------------------------------------------
+castor::server::Mutex::~Mutex() {
+  pthread_mutex_destroy(&m_mutex);
+}
+//------------------------------------------------------------------------------
+//lock
+//------------------------------------------------------------------------------
+void castor::server::Mutex::lock()  {
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutex_lock(&m_mutex),
+    "Error from pthread_mutex_lock in castor::server::Mutex::lock()");
+}
+//------------------------------------------------------------------------------
+//unlock
+//------------------------------------------------------------------------------
+void castor::server::Mutex::unlock()  {
+  castor::exception::Errnum::throwOnReturnedErrno(
+  pthread_mutex_unlock(&m_mutex),
+          "Error from pthread_mutex_unlock in castor::server::Mutex::unlock()");
+}
diff --git a/tapeserver/castor/server/ProcessCap.cpp b/tapeserver/castor/server/ProcessCap.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..34189aa3dd49c5691005932dfea310386df97884
--- /dev/null
+++ b/tapeserver/castor/server/ProcessCap.cpp
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * 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 "castor/exception/Exception.hpp"
+#include "castor/server/ProcessCap.hpp"
+#include "castor/server/SmartCap.hpp"
+#include "common/Utils.hpp"
+
+#include <errno.h>
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+castor::server::ProcessCap::~ProcessCap()
+  throw() {
+}
+
+//------------------------------------------------------------------------------
+// getProcText
+//------------------------------------------------------------------------------
+std::string castor::server::ProcessCap::getProcText() {
+  try {
+    SmartCap cap(getProc());
+    return toText((cap_t)cap.get());
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to get text representation of the capabilities of the process: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// getProc
+//------------------------------------------------------------------------------
+cap_t castor::server::ProcessCap::getProc() {
+  cap_t cap = cap_get_proc();
+  if(NULL == cap) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to get the capabilities of the process: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+  return cap;
+}
+
+//------------------------------------------------------------------------------
+// toText
+//------------------------------------------------------------------------------
+std::string castor::server::ProcessCap::toText(
+  const cap_t cap) {
+  // Create a C++ string with the result of calling cap_to_text()
+  char *const text = cap_to_text(cap, NULL);
+  if(NULL == text) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to create string representation of capability state: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+  std::string result(text);
+
+  // Free the memory allocated by cap_to_text()
+  if(cap_free(text)) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to free string representation of capability state: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+
+  // Return the C++ string
+  return result;
+}
+
+//------------------------------------------------------------------------------
+// setProcText
+//------------------------------------------------------------------------------
+void castor::server::ProcessCap::setProcText(const std::string &text) {
+  try {
+    SmartCap cap(fromText(text));
+    setProc(cap.get());
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to set capabilities of process: " << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// fromText
+//------------------------------------------------------------------------------
+cap_t castor::server::ProcessCap::fromText(const std::string &text) {
+  const cap_t cap = cap_from_text(text.c_str());
+  if(NULL == cap) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to create capability state from string representation"
+      ": text='" << text << "': " << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+
+  return cap;
+}
+
+//------------------------------------------------------------------------------
+// setProc
+//------------------------------------------------------------------------------
+void castor::server::ProcessCap::setProc(const cap_t cap) {
+  if(cap_set_proc(cap)) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to set the capabilities of the process: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+}
diff --git a/tapeserver/castor/server/Semaphores.cpp b/tapeserver/castor/server/Semaphores.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ad79704b8cc9f6855f89d7ef79dc22138ad488f
--- /dev/null
+++ b/tapeserver/castor/server/Semaphores.cpp
@@ -0,0 +1,167 @@
+#include "castor/server/MutexLocker.hpp"
+#include "castor/server/Semaphores.hpp"
+#include "castor/server/Threading.hpp"
+#include "castor/exception/Errnum.hpp"
+#include "castor/exception/Exception.hpp"
+#include <errno.h>
+#include <sys/time.h>
+
+//------------------------------------------------------------------------------
+//PosixSemaphore constructor
+//------------------------------------------------------------------------------
+castor::server::PosixSemaphore::PosixSemaphore(int initial)
+ {
+  castor::exception::Errnum::throwOnReturnedErrno(
+    sem_init(&m_sem, 0, initial),
+    "Error from sem_init in castor::server::PosixSemaphore::PosixSemaphore()");
+}
+//------------------------------------------------------------------------------
+//PosixSemaphore destructor
+//------------------------------------------------------------------------------
+castor::server::PosixSemaphore::~PosixSemaphore() {
+  /* There is a danger of destroying the semaphore in the consumer
+     while the producer is still referring to the object.
+     This mutex prevents this from happening. (The release method locks it). */
+  MutexLocker ml(&m_mutexPosterProtection);
+  sem_destroy(&m_sem);
+}
+//------------------------------------------------------------------------------
+//acquire
+//------------------------------------------------------------------------------
+void castor::server::PosixSemaphore::acquire()
+ {
+  int ret;
+  /* If we receive EINTR, we should just keep trying (signal interruption) */
+  while((ret = sem_wait(&m_sem)) && EINTR == errno) {}
+  /* If it was not EINTR, it's a failure */
+  castor::exception::Errnum::throwOnNonZero(ret,
+    "Error from sem_wait in castor::server::PosixSemaphore::acquire()");
+}
+//------------------------------------------------------------------------------
+//acquire
+//------------------------------------------------------------------------------
+void castor::server::PosixSemaphore::acquireWithTimeout(uint64_t timeout_us)
+ {
+  int ret;
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  struct timespec ts;
+  // Add microseconds
+  ts.tv_nsec = (tv.tv_usec + (timeout_us % 1000000)) * 1000;
+  // Forward carry and add seconds
+  ts.tv_sec = tv.tv_sec + timeout_us / 1000000 + ts.tv_nsec / 1000000000;
+  // Clip what we carried
+  ts.tv_nsec %= 1000000000;
+  /* If we receive EINTR, we should just keep trying (signal interruption) */
+  while((ret = sem_timedwait(&m_sem, &ts)) && EINTR == errno) {}
+  /* If we got a timeout, throw a special exception */
+  if (ret && ETIMEDOUT == errno) { throw Timeout(); }
+  /* If it was not EINTR, it's a failure */
+  castor::exception::Errnum::throwOnNonZero(ret,
+    "Error from sem_wait in castor::server::PosixSemaphore::acquireWithTimeout()");
+}
+
+//------------------------------------------------------------------------------
+//tryAcquire
+//------------------------------------------------------------------------------
+bool castor::server::PosixSemaphore::tryAcquire()
+ {
+  int ret = sem_trywait(&m_sem);
+  if (!ret) return true;
+  if (ret && EAGAIN == errno) return false;
+  castor::exception::Errnum::throwOnNonZero(ret,
+    "Error from sem_trywait in castor::server::PosixSemaphore::tryAcquire()");
+  /* unreacheable, just for compiler happiness */
+  return false;
+}
+//------------------------------------------------------------------------------
+//release
+//------------------------------------------------------------------------------
+void castor::server::PosixSemaphore::release(int n)
+ {
+  for (int i=0; i<n; i++) {
+    MutexLocker ml(&m_mutexPosterProtection);
+    castor::exception::Errnum::throwOnNonZero(sem_post(&m_sem),
+      "Error from sem_post in castor::server::PosixSemaphore::release()");
+  }
+}
+//------------------------------------------------------------------------------
+//CondVarSemaphore constructor
+//------------------------------------------------------------------------------
+castor::server::CondVarSemaphore::CondVarSemaphore(int initial)
+:m_value(initial) {
+      castor::exception::Errnum::throwOnReturnedErrno(
+        pthread_cond_init(&m_cond, NULL),
+        "Error from pthread_cond_init in castor::server::CondVarSemaphore::CondVarSemaphore()");
+      castor::exception::Errnum::throwOnReturnedErrno(
+        pthread_mutex_init(&m_mutex, NULL),
+        "Error from pthread_mutex_init in castor::server::CondVarSemaphore::CondVarSemaphore()");
+    }
+
+//------------------------------------------------------------------------------
+//CondVarSemaphore destructor
+//------------------------------------------------------------------------------
+castor::server::CondVarSemaphore::~CondVarSemaphore() {
+      /* Barrier protecting the last user */
+      pthread_mutex_lock(&m_mutex);
+      pthread_mutex_unlock(&m_mutex);
+      /* Cleanup */
+      pthread_cond_destroy(&m_cond);
+      pthread_mutex_destroy(&m_mutex);
+    }
+//------------------------------------------------------------------------------
+//acquire
+//------------------------------------------------------------------------------
+void castor::server::CondVarSemaphore::acquire()
+ {
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutex_lock(&m_mutex),
+    "Error from pthread_mutex_lock in castor::server::CondVarSemaphore::acquire()");
+  while (m_value <= 0) {
+    castor::exception::Errnum::throwOnReturnedErrno(
+      pthread_cond_wait(&m_cond, &m_mutex),
+      "Error from pthread_cond_wait in castor::server::CondVarSemaphore::acquire()");
+  }
+  m_value--;
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutex_unlock(&m_mutex),
+    "Error from pthread_mutex_unlock in castor::server::CondVarSemaphore::acquire()");
+}
+//------------------------------------------------------------------------------
+//tryAcquire
+//------------------------------------------------------------------------------
+bool castor::server::CondVarSemaphore::tryAcquire()
+ {
+  bool ret;
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutex_lock(&m_mutex),
+      "Error from pthread_mutex_lock in castor::server::CondVarSemaphore::tryAcquire()");
+  if (m_value > 0) {
+    ret = true;
+    m_value--;
+  } else {
+    ret = false;
+  }
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutex_unlock(&m_mutex),
+      "Error from pthread_mutex_unlock in castor::server::CondVarSemaphore::tryAcquire()");
+  return ret;
+}
+//------------------------------------------------------------------------------
+//release
+//------------------------------------------------------------------------------
+void castor::server::CondVarSemaphore::release(int n)
+ {
+  for (int i=0; i<n; i++) {
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutex_lock(&m_mutex),
+      "Error from pthread_mutex_unlock in castor::server::CondVarSemaphore::release()");
+    m_value++;
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_cond_signal(&m_cond),
+      "Error from pthread_cond_signal in castor::server::CondVarSemaphore::release()");
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_mutex_unlock(&m_mutex),
+      "Error from pthread_mutex_unlock in castor::server::CondVarSemaphore::release()");
+  }
+}
diff --git a/tapeserver/castor/server/Semaphores.hpp b/tapeserver/castor/server/Semaphores.hpp
index 082d66b8bfa7bc471b5d49851366d4cf2315a7e6..3ad7d5851f269a8257d16dea7dd59d663a835a72 100644
--- a/tapeserver/castor/server/Semaphores.hpp
+++ b/tapeserver/castor/server/Semaphores.hpp
@@ -25,6 +25,7 @@
 
 #include <pthread.h>
 #include <semaphore.h>
+#include <stdint.h>
 #include "castor/server/Mutex.hpp"
 
 namespace castor {
@@ -35,9 +36,11 @@ namespace server {
    */
   class PosixSemaphore {
   public:
+    class Timeout{};
     PosixSemaphore(int initial = 0) ;
     ~PosixSemaphore();
     void acquire() ;
+    void acquireWithTimeout(uint64_t timeout_us); /**< Throws an exception (Timeout) in case of timeout */
     bool tryAcquire() ;
     void release(int n=1) ;
   private:
diff --git a/tapeserver/castor/server/Threading.cpp b/tapeserver/castor/server/Threading.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9dcc3bb0151da7c994d3336000cd727be1f46011
--- /dev/null
+++ b/tapeserver/castor/server/Threading.cpp
@@ -0,0 +1,90 @@
+/******************************************************************************
+ *
+ * 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 "Threading.hpp"
+#include <errno.h>
+#include <typeinfo>
+#include <stdlib.h>
+#include <cxxabi.h>
+#include "castor/BaseObject.hpp"
+
+/* Implmentations of the threading primitives */
+//------------------------------------------------------------------------------
+//start
+//------------------------------------------------------------------------------
+void castor::server::Thread::start()
+ {
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_create(&m_thread, NULL, pthread_runner, this),
+      "Error from pthread_create in castor::server::Thread::start()");
+}
+//------------------------------------------------------------------------------
+//wait
+//------------------------------------------------------------------------------
+void castor::server::Thread::wait()
+ {
+  castor::exception::Errnum::throwOnReturnedErrno(
+    pthread_join(m_thread, NULL),
+      "Error from pthread_join in castor::server::Thread::wait()");
+  if (m_hadException) {
+    std::string w = "Uncaught exception of type \"";
+    w += m_type;
+    w += "\" in Thread.run():\n>>>>\n";
+    w += m_what;
+    w += "<<<< End of uncaught exception";
+    throw UncaughtExceptionInThread(w);
+  }
+}
+//------------------------------------------------------------------------------
+//pthread_runner
+//------------------------------------------------------------------------------
+void * castor::server::Thread::pthread_runner (void * arg) {
+
+  /* static_casting a pointer to and from void* preserves the address. 
+   * See https://stackoverflow.com/questions/573294/when-to-use-reinterpret-cast
+   */ 
+  Thread * _this = static_cast<Thread *>(arg);
+   
+  // The threading init is needing by many castor components, so better do
+  // it all the time (this should not have side effects)
+  try {
+    _this->run();
+  } catch (std::exception & e) {
+    _this->m_hadException = true;
+    int status = -1;
+    char * demangled = abi::__cxa_demangle(typeid(e).name(), NULL, NULL, &status);
+    if (!status) {
+      _this->m_type += demangled;
+    } else {
+      _this->m_type = typeid(e).name();
+    }
+    free(demangled);
+    _this->m_what = e.what();
+  } catch (...) {
+    _this->m_hadException = true;
+    _this->m_type = "unknown";
+    _this->m_what = "uncaught non-standard exception";
+  }
+  BaseObject::resetServices();
+  return NULL;
+}
diff --git a/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt b/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt
index d1f170ef5ab3d58e58c4daa5a2a6a17e05e01d03..7536f46f99bb1f91234603143c0f386eabffa2ee 100644
--- a/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt
+++ b/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt
@@ -74,12 +74,12 @@ add_library(ctaTapeServerDaemon
   TpconfigLine.cpp
   TpconfigLines.cpp)
 
-target_link_libraries(ctaTapeServerDaemon ctamessages ctatapereactor  ctacommon ctanameserver ctaremotens protobuf ctascheduler)
+target_link_libraries(ctaTapeServerDaemon ctamessages ctatapereactor  ctacommon ctanameserver ctaremotens protobuf ctascheduler ctalegacymsg)
 add_dependencies(ctaTapeServerDaemon ctamessagesprotobuf)
 
 add_executable(cta-tapeserverd TapeDaemon.cpp)
 target_link_libraries(cta-tapeserverd ctaTapeServerDaemon SCSI System Utils 
-  File TapeDrive ctacommon castorclient castorlegacymsg castorserver 
+  File TapeDrive ctacommon castorclient 
   ctatapereactor ${LIBCAP_LIB} ${ZLIB_LIBRARIES} ctamessages zmq)
 install (TARGETS cta-tapeserverd DESTINATION usr/bin)
 
diff --git a/tapeserver/castor/tape/tapeserver/file/CMakeLists.txt b/tapeserver/castor/tape/tapeserver/file/CMakeLists.txt
index 34f5de927906391540e7a66bfff9a685651c9379..d26b42a91ae18ff0bc0fa71f817119a0fb0ac687 100644
--- a/tapeserver/castor/tape/tapeserver/file/CMakeLists.txt
+++ b/tapeserver/castor/tape/tapeserver/file/CMakeLists.txt
@@ -30,7 +30,7 @@ add_library(File
   DiskFile.cpp
   Structures.cpp
   ../exception/XrootCl.cpp)
-target_link_libraries (File castorrfio XrdCl cryptopp)
+target_link_libraries (File castorrfio XrdCl cryptopp ctaserverutils)
 
 add_library(ctatapeserverfileunittests SHARED
   StructuresTest.cpp