blob: 079b8030c0f719e94c00e07697e02a7d058c0abe [file] [log] [blame]
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2018, The University of Memphis
4 *
5 * This file is part of PSync.
6 * See AUTHORS.md for complete list of PSync authors and contributors.
7 *
8 * PSync is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * PSync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * PSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 **/
19
20#ifndef PSYNC_PRODUCER_BASE_HPP
21#define PSYNC_PRODUCER_BASE_HPP
22
23#include "detail/iblt.hpp"
24#include "detail/bloom-filter.hpp"
25#include "detail/util.hpp"
26#include "detail/test-access-control.hpp"
27
28#include <ndn-cxx/face.hpp>
29#include <ndn-cxx/util/scheduler.hpp>
30#include <ndn-cxx/util/time.hpp>
31#include <ndn-cxx/security/key-chain.hpp>
32#include <ndn-cxx/security/validator-config.hpp>
33
34#include <map>
35#include <unordered_set>
36#include <random>
37
38namespace psync {
39
40using namespace ndn::literals::time_literals;
41
42const ndn::time::milliseconds SYNC_REPLY_FRESHNESS = 1_s;
43const ndn::time::milliseconds HELLO_REPLY_FRESHNESS = 1_s;
44
45/**
46 * @brief Base class for PartialProducer and FullProducer
47 *
48 * Contains code common to both
49 */
50class ProducerBase
51{
52 class Error : public std::runtime_error
53 {
54 public:
55 using std::runtime_error::runtime_error;
56 };
57
58PUBLIC_WITH_TESTS_ELSE_PROTECTED:
59 /**
60 * @brief constructor
61 *
62 * @param expectedNumEntries expected number entries in IBF
63 * @param face application's face
64 * @param syncPrefix The prefix of the sync group
65 * @param userPrefix The prefix of the first user in the group
66 * @param syncReplyFreshness freshness of sync data
67 * @param helloReplyFreshness freshness of hello data
68 */
69 ProducerBase(size_t expectedNumEntries,
70 ndn::Face& face,
71 const ndn::Name& syncPrefix,
72 const ndn::Name& userPrefix,
73 ndn::time::milliseconds syncReplyFreshness = SYNC_REPLY_FRESHNESS,
74 ndn::time::milliseconds helloReplyFreshness = HELLO_REPLY_FRESHNESS);
75public:
76 /**
77 * @brief Returns the current sequence number of the given prefix
78 *
79 * @param prefix prefix to get the sequence number of
80 */
81 ndn::optional<uint64_t>
82 getSeqNo(const ndn::Name& prefix) const
83 {
84 auto it = m_prefixes.find(prefix);
85 if (it == m_prefixes.end()) {
86 return ndn::nullopt;
87 }
88 return it->second;
89 }
90
91 /**
92 * @brief Adds a user node for synchronization
93 *
94 * Initializes m_prefixes[prefix] to zero
95 * Does not add zero-th sequence number to IBF
96 * because if a large number of user nodes are added
97 * then decoding of the difference between own IBF and
98 * other IBF will not be possible
99 *
100 * @param prefix the user node to be added
101 */
102 bool
103 addUserNode(const ndn::Name& prefix);
104
105 /**
106 * @brief Remove the user node from synchronization
107 *
108 * Erases prefix from IBF and other maps
109 *
110 * @param prefix the user node to be removed
111 */
112 void
113 removeUserNode(const ndn::Name& prefix);
114
115PUBLIC_WITH_TESTS_ELSE_PROTECTED:
116 /**
117 * @brief Update m_prefixes and IBF with the given prefix and seq
118 *
119 * Whoever calls this needs to make sure that prefix is in m_prefixes
120 * We remove already existing prefix/seq from IBF
121 * (unless seq is zero because we don't insert zero seq into IBF)
122 * Then we update m_prefix, m_prefix2hash, m_hash2prefix, and IBF
123 *
124 * @param prefix prefix of the update
125 * @param seq sequence number of the update
126 */
127 void
128 updateSeqNo(const ndn::Name& prefix, uint64_t seq);
129
130 bool
131 isUserNode(const ndn::Name& prefix) {
132 if (m_prefixes.find(prefix) == m_prefixes.end()) {
133 return false;
134 }
135 return true;
136 }
137
138 /**
139 * @brief Sends a data packet with content type nack
140 *
141 * Producer sends a nack to consumer if consumer has very old IBF
142 * whose differences with latest IBF can't be decoded successfully
143 *
144 * @param name send application nack with this name
145 */
146 void
147 sendApplicationNack(const ndn::Name& name);
148
149 /**
150 * @brief Logs a message if setting an interest filter fails
151 *
152 * @param prefix
153 * @param msg
154 */
155 void
156 onRegisterFailed(const ndn::Name& prefix, const std::string& msg) const;
157
158PUBLIC_WITH_TESTS_ELSE_PROTECTED:
159 IBLT m_iblt;
160 uint32_t m_expectedNumEntries;
161 // Threshold is used check if the differences are greater
162 // than it and whether we need to update the other side.
163 uint32_t m_threshold;
164
165 // prefix and sequence number
166 std::map <ndn::Name, uint64_t> m_prefixes;
167 // Just for looking up hash faster (instead of calculating it again)
168 // Only used in updateSeqNo, prefix/seqNo is the key
169 std::map <ndn::Name, uint32_t> m_prefix2hash;
170 // Value is prefix (and not prefix/seqNo)
171 std::map <uint32_t, ndn::Name> m_hash2prefix;
172
173 ndn::Face& m_face;
174 ndn::KeyChain m_keyChain;
175 ndn::Scheduler m_scheduler;
176
177 ndn::Name m_syncPrefix;
178 ndn::Name m_userPrefix;
179
180 ndn::time::milliseconds m_syncReplyFreshness;
181 ndn::time::milliseconds m_helloReplyFreshness;
182
183 std::mt19937 m_rng;
184};
185
186} // namespace psync
187
188#endif // PSYNC_PRODUCER_BASE_HPP