1 /**
2  * Copyright (c) 2019 Paul-Louis Ageneau
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #ifndef RTC_IMPL_TRANSPORT_H
20 #define RTC_IMPL_TRANSPORT_H
21 
22 #include "common.hpp"
23 #include "internals.hpp"
24 #include "message.hpp"
25 
26 #include <atomic>
27 #include <functional>
28 #include <memory>
29 
30 namespace rtc::impl {
31 
32 class Transport {
33 public:
34 	enum class State { Disconnected, Connecting, Connected, Completed, Failed };
35 	using state_callback = std::function<void(State state)>;
36 
Transport(shared_ptr<Transport> lower=nullptr,state_callback callback=nullptr)37 	Transport(shared_ptr<Transport> lower = nullptr, state_callback callback = nullptr)
38 	    : mLower(std::move(lower)), mStateChangeCallback(std::move(callback)) {}
39 
~Transport()40 	virtual ~Transport() { stop(); }
41 
start()42 	virtual void start() { mStopped = false; }
43 
stop()44 	virtual bool stop() {
45 		if (mStopped.exchange(true))
46 			return false;
47 
48 		// We don't want incoming() to be called by the lower layer anymore
49 		if (mLower) {
50 			PLOG_VERBOSE << "Unregistering incoming callback";
51 			mLower->onRecv(nullptr);
52 		}
53 		return true;
54 	}
55 
registerIncoming()56 	void registerIncoming() {
57 		if (mLower) {
58 			PLOG_VERBOSE << "Registering incoming callback";
59 			mLower->onRecv(std::bind(&Transport::incoming, this, std::placeholders::_1));
60 		}
61 	}
62 
onRecv(message_callback callback)63 	void onRecv(message_callback callback) { mRecvCallback = std::move(callback); }
onStateChange(state_callback callback)64 	void onStateChange(state_callback callback) { mStateChangeCallback = std::move(callback); }
state() const65 	State state() const { return mState; }
66 
send(message_ptr message)67 	virtual bool send(message_ptr message) { return outgoing(message); }
68 
69 protected:
recv(message_ptr message)70 	void recv(message_ptr message) {
71 		try {
72 			mRecvCallback(message);
73 		} catch (const std::exception &e) {
74 			PLOG_WARNING << e.what();
75 		}
76 	}
changeState(State state)77 	void changeState(State state) {
78 		try {
79 			if (mState.exchange(state) != state)
80 				mStateChangeCallback(state);
81 		} catch (const std::exception &e) {
82 			PLOG_WARNING << e.what();
83 		}
84 	}
85 
incoming(message_ptr message)86 	virtual void incoming(message_ptr message) { recv(message); }
outgoing(message_ptr message)87 	virtual bool outgoing(message_ptr message) {
88 		if (mLower)
89 			return mLower->send(message);
90 		else
91 			return false;
92 	}
93 
94 private:
95 	const shared_ptr<Transport> mLower;
96 	synchronized_callback<State> mStateChangeCallback;
97 	synchronized_callback<message_ptr> mRecvCallback;
98 
99 	std::atomic<State> mState = State::Disconnected;
100 	std::atomic<bool> mStopped = true;
101 };
102 
103 } // namespace rtc::impl
104 
105 #endif
106