Leosac  0.8.0
Open Source Access Control
NotifierInstance.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014-2016 Leosac
3 
4  This file is part of Leosac.
5 
6  Leosac is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Affero General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Leosac is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Affero General Public License for more details.
15 
16  You should have received a copy of the GNU Affero General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "NotifierInstance.hpp"
21 #include "core/auth/Auth.hpp"
23 #include "tools/Colorize.hpp"
24 #include "tools/log.hpp"
25 #include <zmqpp/message.hpp>
26 
27 using namespace Leosac;
28 using namespace Leosac::Module;
29 using namespace Leosac::Module::TCPNotifier;
30 
31 NotifierInstance::NotifierInstance(zmqpp::context &ctx, zmqpp::reactor &reactor,
32  std::vector<std::string> auth_sources,
33  std::vector<std::string> connect_to,
34  std::vector<std::string> bind_to,
35  ProtocolHandlerUPtr protocol_handler)
36  : bus_sub_(ctx, zmqpp::socket_type::sub)
37  , tcp_(ctx, zmqpp::socket_type::stream)
38  , protocol_(std::move(protocol_handler))
39 {
40  ASSERT_LOG(connect_to.empty() || bind_to.empty(),
41  "Cannot bind and connect at the same time.");
42  ASSERT_LOG(!connect_to.empty() || !bind_to.empty(), "Cannot do nothing");
43  ASSERT_LOG(protocol_, "No protocol handler");
44 
45  act_as_server_ = !bind_to.empty();
46 
47  bus_sub_.connect("inproc://zmq-bus-pub");
48  for (const auto &src : auth_sources)
49  {
50  bus_sub_.subscribe("S_" + src);
51  }
52  reactor.add(bus_sub_, std::bind(&NotifierInstance::handle_msg_bus, this));
53 
54  configure_tcp_socket(act_as_server_ ? bind_to : connect_to);
55  reactor.add(tcp_, std::bind(&NotifierInstance::handle_tcp_msg, this));
56 }
57 
59 {
60  for (const auto &target : targets_)
61  {
62  // Skip disconnected client.
63  if (!target.status_)
64  continue;
65  zmqpp::message msg;
66 
67  msg << target.zmq_identity_;
68  try
69  {
70  auto data = protocol_->build_cred_msg(card);
71  msg.add_raw(&data[0], data.size());
72  }
73  catch (const ProtocolException &e)
74  {
75  WARN("TCPNotifier: Protocol error: " << e.what());
76  continue;
77  }
78  auto ret = tcp_.send(msg, true);
79  if (ret == false) // would block. woops
80  {
81  ERROR("Sending to client would block.");
82  }
83  }
84 }
85 
86 void NotifierInstance::handle_one(zmqpp::message &msg)
87 {
88  std::string routing_id;
89  std::string data;
90 
91  assert(msg.parts() == 2);
92  msg >> routing_id >> data;
93 
94  if (data.size() == 0)
95  {
96  auto target = find_target(routing_id);
97  if (act_as_server_)
98  {
99  // As a server we drop disconnected peer, or create a TargetInfo
100  // for newly connected peer.
101  if (!target)
102  {
103  TargetInfo ti;
104  ti.status_ = true;
105  ti.zmq_identity_ = routing_id;
106 
107  targets_.push_back(std::move(ti));
108  INFO("TCP-Notifier: New client connected.");
109  }
110  else
111  {
112  targets_.erase(std::remove_if(targets_.begin(), targets_.end(),
113  [&](const TargetInfo &info) {
114  return info.zmq_identity_ ==
115  routing_id;
116  }),
117  targets_.end());
118  INFO("TCP-Notifier: Client disconnected.");
119  }
120  return;
121  }
122  ASSERT_LOG(target, "Why did we lose a target?");
123 
124  if (target->status_)
125  INFO("Lost connection with client.");
126  else
127  INFO("Successfully connected to client.");
128 
129  target->status_ = !target->status_;
130  }
131 }
132 
134 {
135  zmqpp::message msg;
136 
137  while (tcp_.receive(msg, true))
138  {
139  handle_one(msg);
140  }
141 }
142 
144 NotifierInstance::find_target(const std::string &routing_id)
145 {
146  auto itr = std::find_if(targets_.begin(), targets_.end(),
147  [&](const TargetInfo &target) {
148  return target.zmq_identity_ == routing_id;
149  });
150  if (itr != targets_.end())
151  return &(*itr);
152  return nullptr;
153 }
154 
156 {
157  zmqpp::message msg;
158  std::string src;
160  std::string card;
161  int bits;
162 
163  bus_sub_.receive(msg);
164  if (msg.parts() < 4)
165  {
166  WARN("Unexpected message content.");
167  return;
168  }
169  msg >> src >> type >> card >> bits;
171  {
172  INFO("TCP-Notifier cannot handle this type of credential yet.");
173  return;
174  }
175  auto wiegand_card = std::make_shared<Cred::RFIDCard>();
176  wiegand_card->card_id(card);
177  wiegand_card->nb_bits(bits);
178 
179  handle_credential(*wiegand_card);
180 }
181 
183  const std::vector<std::string> &endpoints)
184 {
185  tcp_.set(zmqpp::socket_option::backlog, 5);
186  if (act_as_server_)
187  {
188  for (auto &endpoint : endpoints)
189  {
190  INFO("TCP-Notifier binding to: tcp://" << endpoint);
191  tcp_.bind("tcp://" + endpoint);
192  }
193  }
194  else
195  {
196  for (auto &endpoint : endpoints)
197  {
198  TargetInfo target;
199  target.url_ = "tcp://" + endpoint;
200  target.status_ = false;
201  tcp_.connect(target.url_);
202  INFO("TCP-Notifier remote target: " << Colorize::green(target.url_));
203  tcp_.get(zmqpp::socket_option::identity, target.zmq_identity_);
204  targets_.push_back(std::move(target));
205  }
206  }
207 }
Leosac::Module::TCPNotifier::NotifierInstance::act_as_server_
bool act_as_server_
Are we a server or a client ?
Definition: NotifierInstance.hpp:151
Leosac::Module::TCPNotifier::NotifierInstance::handle_one
void handle_one(zmqpp::message &msg)
Definition: NotifierInstance.cpp:86
Leosac::Module::TCPNotifier::NotifierInstance::TargetInfo::zmq_identity_
std::string zmq_identity_
Definition: NotifierInstance.hpp:126
WARN
@ WARN
Definition: log.hpp:33
zmqpp
Definition: CoreUtils.hpp:27
ERROR
@ ERROR
Definition: log.hpp:32
Auth.hpp
ASSERT_LOG
#define ASSERT_LOG(cond, msg)
Definition: log.hpp:190
Leosac::Module::TCPNotifier::NotifierInstance::handle_msg_bus
void handle_msg_bus()
Definition: NotifierInstance.cpp:155
RFIDCard.hpp
INFO
@ INFO
Definition: log.hpp:34
Leosac::Module::TCPNotifier::NotifierInstance::configure_tcp_socket
void configure_tcp_socket(const std::vector< std::string > &endpoints)
Definition: NotifierInstance.cpp:182
Leosac::Cred::RFIDCard
An RFID card credential.
Definition: RFIDCard.hpp:33
Colorize.hpp
Leosac::Module
All modules that provides features to Leosac shall be in this namespace.
Leosac::Module::TCPNotifier::ProtocolHandlerUPtr
std::unique_ptr< ProtocolHandler > ProtocolHandlerUPtr
Definition: ProtocolHandler.hpp:38
Leosac::Module::TCPNotifier::NotifierInstance::protocol_
ProtocolHandlerUPtr protocol_
Definition: NotifierInstance.hpp:146
Leosac
This is the header file for a generated source file, GitSHA1.cpp.
Definition: APIStatusCode.hpp:22
Leosac::Module::TCPNotifier::NotifierInstance::handle_tcp_msg
void handle_tcp_msg()
Some event on our ZMQ Stream socket.
Definition: NotifierInstance.cpp:133
Leosac::Colorize::green
std::string green(const T &in)
Definition: Colorize.hpp:82
Leosac::Module::TCPNotifier
Definition: NotifierInstance.hpp:33
Leosac::Module::TCPNotifier::NotifierInstance::TargetInfo::url_
std::string url_
Definition: NotifierInstance.hpp:123
Leosac::Module::TCPNotifier::NotifierInstance::tcp_
zmqpp::socket tcp_
Stream socket used to connect to remote client we want to notify.
Definition: NotifierInstance.hpp:142
log.hpp
Leosac::Module::TCPNotifier::NotifierInstance::TargetInfo::status_
bool status_
Definition: NotifierInstance.hpp:130
Leosac::Module::TCPNotifier::NotifierInstance::find_target
TargetInfo * find_target(const std::string &routing_id)
Attempt to find a target from its routing_id.
Definition: NotifierInstance.cpp:144
Leosac::Module::TCPNotifier::NotifierInstance::handle_credential
void handle_credential(Cred::RFIDCard &card)
Notify the peers of the card credential.
Definition: NotifierInstance.cpp:58
Leosac::Module::TCPNotifier::NotifierInstance::targets_
std::list< TargetInfo > targets_
Definition: NotifierInstance.hpp:144
Leosac::Module::TCPNotifier::NotifierInstance::NotifierInstance
NotifierInstance(zmqpp::context &ctx, zmqpp::reactor &reactor, std::vector< std::string > auth_sources, std::vector< std::string > connect_to, std::vector< std::string > bind_to, ProtocolHandlerUPtr protocol_handler)
Create a new notifier instance.
Definition: NotifierInstance.cpp:31
Leosac::Auth::SourceType
SourceType
Definition: Auth.hpp:29
Leosac::Module::TCPNotifier::ProtocolException
An specialized exception that ProtocolHandler can throw when converting the credential to a message f...
Definition: ProtocolHandler.hpp:46
Leosac::Module::TCPNotifier::NotifierInstance::bus_sub_
zmqpp::socket bus_sub_
Read internal message bus.
Definition: NotifierInstance.hpp:136
Leosac::Auth::SourceType::SIMPLE_WIEGAND
@ SIMPLE_WIEGAND
This define message formatting for data source SIMPLE_WIEGAND.
Leosac::Module::TCPNotifier::NotifierInstance::TargetInfo
Some information for each tcp server target.
Definition: NotifierInstance.hpp:110
NotifierInstance.hpp