summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2020-04-16 00:38:08 +0200
committerCarl Hetherington <cth@carlh.net>2020-04-17 00:42:54 +0200
commit3f2bec7b6ee2f27b2de056cdc0137744d2e9e253 (patch)
tree34e0d9f72abe35e8e477d92036444d9c47fb7e28 /src/lib
parent5f4a41f20a189ec2863760cd1f5117435277f40f (diff)
Add feature to Socket so that it can send digests of data it has sent
and check those digests on receive.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/dcpomatic_socket.cc109
-rw-r--r--src/lib/dcpomatic_socket.h33
-rw-r--r--src/lib/digester.cc14
-rw-r--r--src/lib/digester.h4
4 files changed, 159 insertions, 1 deletions
diff --git a/src/lib/dcpomatic_socket.cc b/src/lib/dcpomatic_socket.cc
index ca910bb79..a0a7a1cf3 100644
--- a/src/lib/dcpomatic_socket.cc
+++ b/src/lib/dcpomatic_socket.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
@@ -21,12 +21,16 @@
#include "dcpomatic_socket.h"
#include "compose.hpp"
#include "exceptions.h"
+#include "dcpomatic_assert.h"
#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include "i18n.h"
+using boost::shared_ptr;
+using boost::weak_ptr;
+
/** @param timeout Timeout in seconds */
Socket::Socket (int timeout)
: _deadline (_io_service)
@@ -89,6 +93,10 @@ Socket::write (uint8_t const * data, int size)
if (ec) {
throw NetworkError (String::compose (_("error during async_write (%1)"), ec.value ()));
}
+
+ if (_write_digester) {
+ _write_digester->add (data, static_cast<size_t>(size));
+ }
}
void
@@ -117,6 +125,10 @@ Socket::read (uint8_t* data, int size)
if (ec) {
throw NetworkError (String::compose (_("error during async_read (%1)"), ec.value ()));
}
+
+ if (_read_digester) {
+ _read_digester->add (data, static_cast<size_t>(size));
+ }
}
uint32_t
@@ -126,3 +138,98 @@ Socket::read_uint32 ()
read (reinterpret_cast<uint8_t *> (&v), 4);
return ntohl (v);
}
+
+
+void
+Socket::start_read_digest ()
+{
+ DCPOMATIC_ASSERT (!_read_digester);
+ _read_digester.reset (new Digester());
+}
+
+void
+Socket::start_write_digest ()
+{
+ DCPOMATIC_ASSERT (!_write_digester);
+ _write_digester.reset (new Digester());
+}
+
+
+Socket::ReadDigestScope::ReadDigestScope (shared_ptr<Socket> socket)
+ : _socket (socket)
+{
+ socket->start_read_digest ();
+}
+
+
+bool
+Socket::ReadDigestScope::check ()
+{
+ shared_ptr<Socket> sp = _socket.lock ();
+ if (!sp) {
+ return false;
+ }
+
+ return sp->check_read_digest ();
+}
+
+
+Socket::WriteDigestScope::WriteDigestScope (shared_ptr<Socket> socket)
+ : _socket (socket)
+{
+ socket->start_write_digest ();
+}
+
+
+Socket::WriteDigestScope::~WriteDigestScope ()
+{
+ shared_ptr<Socket> sp = _socket.lock ();
+ if (sp) {
+ try {
+ sp->finish_write_digest ();
+ } catch (...) {
+ /* If we can't write our digest, something bad has happened
+ * so let's just let it happen.
+ */
+ }
+ }
+}
+
+
+bool
+Socket::check_read_digest ()
+{
+ DCPOMATIC_ASSERT (_read_digester);
+ int const size = _read_digester->size ();
+
+ uint8_t ref[size];
+ _read_digester->get (ref);
+
+ /* Make sure _read_digester is gone before we call read() so that the digest
+ * isn't itself digested.
+ */
+ _read_digester.reset ();
+
+ uint8_t actual[size];
+ read (actual, size);
+
+ return memcmp(ref, actual, size) == 0;
+}
+
+void
+Socket::finish_write_digest ()
+{
+ DCPOMATIC_ASSERT (_write_digester);
+ int const size = _write_digester->size();
+
+ uint8_t buffer[size];
+ _write_digester->get (buffer);
+
+ /* Make sure _write_digester is gone before we call write() so that the digest
+ * isn't itself digested.
+ */
+ _write_digester.reset ();
+
+ write (buffer, size);
+}
+
diff --git a/src/lib/dcpomatic_socket.h b/src/lib/dcpomatic_socket.h
index 870e7315c..1fa0b046f 100644
--- a/src/lib/dcpomatic_socket.h
+++ b/src/lib/dcpomatic_socket.h
@@ -18,8 +18,11 @@
*/
+#include "digester.h"
#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/weak_ptr.hpp>
/** @class Socket
* @brief A class to wrap a boost::asio::ip::tcp::socket with some things
@@ -46,8 +49,36 @@ public:
void read (uint8_t* data, int size);
uint32_t read_uint32 ();
+ class ReadDigestScope
+ {
+ public:
+ ReadDigestScope (boost::shared_ptr<Socket> socket);
+ bool check ();
+ private:
+ boost::weak_ptr<Socket> _socket;
+ };
+
+ /** After one of these is created everything that is sent from the socket will be
+ * added to a digest. When the DigestScope is destroyed the digest will be sent
+ * from the socket.
+ */
+ class WriteDigestScope
+ {
+ public:
+ WriteDigestScope (boost::shared_ptr<Socket> socket);
+ ~WriteDigestScope ();
+ private:
+ boost::weak_ptr<Socket> _socket;
+ };
+
private:
+ friend class DigestScope;
+
void check ();
+ void start_read_digest ();
+ bool check_read_digest ();
+ void start_write_digest ();
+ void finish_write_digest ();
Socket (Socket const &);
@@ -55,4 +86,6 @@ private:
boost::asio::deadline_timer _deadline;
boost::asio::ip::tcp::socket _socket;
int _timeout;
+ boost::scoped_ptr<Digester> _read_digester;
+ boost::scoped_ptr<Digester> _write_digester;
};
diff --git a/src/lib/digester.cc b/src/lib/digester.cc
index 7bcc77646..452452ba4 100644
--- a/src/lib/digester.cc
+++ b/src/lib/digester.cc
@@ -19,6 +19,7 @@
*/
#include "digester.h"
+#include "dcpomatic_assert.h"
#include <nettle/md5.h>
#include <iomanip>
#include <cstdio>
@@ -67,3 +68,16 @@ Digester::get () const
return _digest.get ();
}
+
+void
+Digester::get (uint8_t* buffer) const
+{
+ md5_digest (&_context, MD5_DIGEST_SIZE, buffer);
+}
+
+
+int
+Digester::size () const
+{
+ return MD5_DIGEST_SIZE;
+}
diff --git a/src/lib/digester.h b/src/lib/digester.h
index bec1f6416..6cdaf2331 100644
--- a/src/lib/digester.h
+++ b/src/lib/digester.h
@@ -40,6 +40,10 @@ public:
std::string get () const;
+ void get (uint8_t* buffer) const;
+
+ int size () const;
+
private:
mutable md5_ctx _context;
mutable boost::optional<std::string> _digest;