]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[805] Interface of the socket requestor
authorMichal 'vorner' Vaner <michal.vaner@nic.cz>
Wed, 21 Dec 2011 13:21:28 +0000 (14:21 +0100)
committerMichal 'vorner' Vaner <michal.vaner@nic.cz>
Wed, 21 Dec 2011 13:21:28 +0000 (14:21 +0100)
Only the test initialization and the singleton accessor functions are
implemented for now (and tests for those).

src/lib/server_common/Makefile.am
src/lib/server_common/socket_request.cc [new file with mode: 0644]
src/lib/server_common/socket_request.h [new file with mode: 0644]
src/lib/server_common/tests/Makefile.am
src/lib/server_common/tests/socket_requestor_test.cc [new file with mode: 0644]

index c2779b4466180f09b61b85886245d79434026a4f..714e25f8595d14c58ea72ddc0f02774303ba5f1b 100644 (file)
@@ -21,6 +21,7 @@ libserver_common_la_SOURCES = client.h client.cc
 libserver_common_la_SOURCES += keyring.h keyring.cc
 libserver_common_la_SOURCES += portconfig.h portconfig.cc
 libserver_common_la_SOURCES += logger.h logger.cc
+libserver_common_la_SOURCES += socket_request.h socket_request.cc
 nodist_libserver_common_la_SOURCES = server_common_messages.h
 nodist_libserver_common_la_SOURCES += server_common_messages.cc
 libserver_common_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/lib/server_common/socket_request.cc b/src/lib/server_common/socket_request.cc
new file mode 100644 (file)
index 0000000..328816f
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "socket_request.h"
+
+namespace isc {
+namespace server_common {
+
+namespace {
+SocketRequestor* requestor(NULL);
+}
+
+SocketRequestor&
+socketRequestor() {
+    if (requestor != NULL) {
+        return (*requestor);
+    } else {
+        isc_throw(InvalidOperation, "The socket requestor is not initialized");
+    }
+}
+
+void
+SocketRequestor::initTest(SocketRequestor* new_requestor) {
+    requestor = new_requestor;
+}
+
+}
+}
diff --git a/src/lib/server_common/socket_request.h b/src/lib/server_common/socket_request.h
new file mode 100644 (file)
index 0000000..f5e71ca
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __SOCKET_REQUEST_H
+#define __SOCKET_REQUEST_H 1
+
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+#include <utility>
+#include <string>
+#include <stdint.h>
+
+namespace isc {
+
+namespace config {
+class ModuleCCSession;
+};
+
+namespace server_common {
+
+/// \brief A singleton class for requesting sockets
+///
+/// This class allows requesting sockets from the socket creator.
+///
+/// It is considered to be a singleton - a class which is instantiated
+/// at most once in the whole application. This is because it makes no
+/// sense to have two of them.
+///
+/// This is actually an abstract base class. There'll be one with
+/// hidden implementation and we expect the tests to create it's own
+/// subclass when needed.
+///
+/// \see socketRequestor function to access the object of this class.
+class SocketRequestor : boost::noncopyable {
+protected:
+    /// \brief Protected constructor
+    ///
+    /// The constructor is protected so this class is not created by accident
+    /// (which it can't anyway, as it has pure virtual methods, but just to
+    /// be sure).
+    SocketRequestor() {}
+public:
+    /// \brief virtual destructor
+    ///
+    /// A virtual destructor, as we have virtual methods, to make sure it is
+    /// destroyed by the destructor of the subclass. This shouldn't matter, as
+    /// a singleton class wouldn't get destroyed, but just to be sure.
+
+    virtual ~ SocketRequestor() {}
+    /// \brief A representation of received socket
+    ///
+    /// The pair holds two parts. The OS-level file descriptor acting as the
+    /// socket (you might want to use it directly with functions like recv,
+    /// or fill it into an asio socket). The other part is the token representing
+    /// the socket, which allows it to be given up again.
+    typedef std::pair<int, std::string> SocketID;
+
+    /// \brief The protocol of requested socket
+    ///
+    /// This describes which protocol the socket should have when created.
+    enum Protocol {
+        UDP,
+        TCP
+    };
+
+    /// \brief The share mode of the requested socket
+    ///
+    /// The socket creator is able to "borrow" the same socket to multiple
+    /// applications at once. However, it isn't always what is required. This
+    /// describes the restrains we want to have on our socket regarding the
+    /// sharing. Union of restriction of all requests on the given socket
+    /// is taken (so you still don't have to get your socket even if you
+    /// say SHARE_ANY, because someone else might already asked for the socket
+    /// with DONT_SHARE).
+    enum ShareMode {
+        DONT_SHARE, //< Request an exclusive ownership of the socket.
+        SHARE_SAME, //< It is possible to share the socket with anybody who
+                    //< provided the same share_name.
+        SHARE_ANY   //< Any sharing is allowed.
+    };
+
+    /// \brief Exception when we can't manipulate a socket
+    ///
+    /// This is thrown if the other side doesn't want to comply to our
+    /// requests, like when we ask for a socket already held by someone
+    /// else or ask for nonsense (releasing a socket we don't own).
+    class SocketError : public Exception {
+    public:
+        SocketError(const char* file, size_t line, const char *what) :
+            Exception(file, line, what)
+        { }
+    };
+
+    /// \brief Ask for a socket
+    ///
+    /// Asks the socket creator to give us a socket. The socket will be bound
+    /// to the given address and port.
+    ///
+    /// \param protocol specifies the protocol of the socket.
+    /// \param address to which the socket should be bound.
+    /// \param port the port to which the socket should be bound (native endian,
+    ///     not network byte order).
+    /// \param share_mode how the socket can be shared with other requests.
+    /// \param share_name the name of sharing group, relevant for SHARE_SAME
+    ///     (specified by us or someone else).
+    /// \return the socket, as a file descriptor and token representing it on
+    ///     the socket creator side.
+    /// \throw CCSessionError when we have a problem talking over the CC
+    ///     session.
+    /// \throw SocketError in case the other side doesn't want to give us
+    ///     the socket for some reason (common cases are when the socket
+    ///     can't be allocated or bound, or when the socket is claimed by
+    ///     some other application and the sharing parameters don't allow
+    ///     sharing it).
+    virtual SocketID requestSocket(Protocol protocol,
+                                   const std::string& address,
+                                   uint16_t port, ShareMode share_mode,
+                                   const std::string& share_name) = 0;
+
+    /// \brief Tell the socket creator we no longer need the socket
+    ///
+    /// Releases the identified socket. This must be called *after*
+    /// the file descriptor was closed on our side. This will allow
+    /// the remote side to either give it to some other application
+    /// or close it, depending on the situation.
+    ///
+    /// \param token the token representing the socket, as received
+    ///     in the second part of the requestSocket result.
+    /// \throw CCSessionError when we have a problem talking over the CC
+    ///     session.
+    /// \throw SocketError in case the other side doesn't like the
+    ///     release (like we're trying to release a socket that doesn't
+    ///     belong to us or exist at all).
+    virtual void releaseSocket(const std::string& token) = 0;
+
+    /// \brief Initialize the singleton object
+    ///
+    /// This creates the object that will be used to request sockets.
+    /// It can be called only once per the life of application.
+    ///
+    /// \param session the CC session that'll be used to talk to the
+    ///     socket creator.
+    /// \throw InvalidOperation when it is called more than once.
+    static void init(config::ModuleCCSession& session);
+
+    /// \brief Initialization for tests
+    ///
+    /// This is to support different subclasses in tests. It replaces
+    /// the object used by socketRequestor() function by this one provided
+    /// as parameter. The ownership is not taken, eg. it's up to the caller
+    /// to delete it when necessary.
+    ///
+    /// This is not to be used in production applications. It is meant as
+    /// an replacement of init.
+    ///
+    /// This never throws.
+    ///
+    /// \param requestor the object to be used. It can be NULL to reset to
+    ///     an "virgin" state (which acts as if initTest or init was never
+    ///     called before).
+    static void initTest(SocketRequestor* requestor);
+};
+
+/// \brief Access the requestor object.
+///
+/// This returns the singleton object for the Requestor.
+///
+/// \return the active socket requestor object.
+/// \throw InvalidOperation if the object was not yet initialized.
+/// \see SocketRequestor::init to initialize the object.
+SocketRequestor&
+socketRequestor();
+
+}
+}
+
+#endif
index d7e113af1c1921633cb7ca1957bc003e0bd520cc..b059d4766b176ece07765c6fd7f58e966cecd626 100644 (file)
@@ -29,6 +29,7 @@ run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += client_unittest.cc
 run_unittests_SOURCES += portconfig_unittest.cc
 run_unittests_SOURCES += keyring_test.cc
+run_unittests_SOURCES += socket_requestor_test.cc
 nodist_run_unittests_SOURCES = data_path.h
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/lib/server_common/tests/socket_requestor_test.cc b/src/lib/server_common/tests/socket_requestor_test.cc
new file mode 100644 (file)
index 0000000..6d49aaa
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <server_common/socket_request.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::server_common;
+using namespace isc;
+
+namespace {
+
+// Check it throws an exception when it is not initialized
+TEST(SocketRequestorAccess, unitialized) {
+    // Make sure it is not initialized
+    SocketRequestor::initTest(NULL);
+    EXPECT_THROW(socketRequestor(), InvalidOperation);
+}
+
+// It returns whatever it is initialized to
+TEST(SocketRequestorAccess, initialized) {
+    // A concrete implementation that does nothing, just can exist
+    class DummyRequestor : public SocketRequestor {
+    public:
+        DummyRequestor() : SocketRequestor() {}
+        virtual void releaseSocket(const std::string&) {}
+        virtual SocketID requestSocket(Protocol, const std::string&, uint16_t,
+                                       ShareMode, const std::string&)
+        {
+            return (SocketID(0, "")); // Just to silence warnings
+        }
+    };
+    DummyRequestor requestor;
+    // Make sure it is initialized (the test way, of course)
+    SocketRequestor::initTest(&requestor);
+    // It returs the same "pointer" as inserted
+    // The casts are there as the template system seemed to get confused
+    // without them, the types should be correct even without them, but
+    // the EXPECT_EQ wanted to use long long int instead of pointers.
+    EXPECT_EQ(static_cast<const SocketRequestor*>(&requestor),
+              static_cast<const SocketRequestor*>(&socketRequestor()));
+    // Just that we don't have an invalid pointer anyway
+    SocketRequestor::initTest(NULL);
+}
+
+}