neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
tcp_packet_stream_server.hpp
Go to the documentation of this file.
1// tcp_packet_stream_server.hpp
2/*
3 * Copyright (c) 2007 Leigh Johnston.
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * * Neither the name of Leigh Johnston nor the names of any
19 * other contributors to this software may be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*/
35
36#pragma once
37
38#include <neolib/neolib.hpp>
39#include <stdexcept>
40#include <vector>
41#include <memory>
45
46namespace neolib
47{
48 template <typename PacketType>
49 class tcp_packet_stream_server;
50
51 template <typename PacketType>
53 {
55 // types
56 public:
57 typedef PacketType packet_type;
60 // events
61 public:
62 define_event(PacketStreamAdded, packet_stream_added, packet_stream_type&)
64 define_event(FailedToAcceptPacketStream, failed_to_accept_packet_stream, const boost::system::error_code&)
65 // types
66 private:
67 typedef typename packet_stream_type::pointer packet_stream_pointer;
68 typedef std::vector<packet_stream_pointer> stream_list;
69 typedef protocol_type::endpoint endpoint_type;
70 typedef protocol_type::resolver resolver_type;
71 typedef protocol_type::acceptor acceptor_type;
72 private:
73 class handler_proxy
74 {
75 public:
76 handler_proxy(self_type& aParent) : iParentDestroyed{ aParent }, iParent{ aParent }
77 {
78 }
79 public:
80 void operator()(const boost::system::error_code& aError)
81 {
82 if (iParentDestroyed)
83 return;
84 iParent.handle_accept(aError);
85 }
86 private:
87 destroyed_flag iParentDestroyed;
88 self_type& iParent;
89 };
90
91 // exceptions
92 public:
93 struct failed_to_resolve_local_host : std::runtime_error { failed_to_resolve_local_host() : std::runtime_error("neolib::tcp_packet_stream_server::failed_to_resolve_local_host") {} };
94 struct stream_not_found : std::logic_error { stream_not_found() : std::logic_error("neolib::tcp_packet_stream_server::stream_not_found") {} };
95
96 // construction
97 public:
98 tcp_packet_stream_server(i_async_task& aIoTask, unsigned short aLocalPort, bool aSecure = false, protocol_family aProtocolFamily = IPv4) :
99 iIoTask(aIoTask),
100 iHandlerProxy(new handler_proxy(*this)),
101 iLocalPort(aLocalPort),
102 iSecure(aSecure),
103 iProtocolFamily(aProtocolFamily & IPv4 ? protocol_type::v4() : protocol_type::v6()),
104 iLocalEndpoint(iProtocolFamily, iLocalPort),
105 iAcceptor(aIoTask.io_service().native_object<boost::asio::io_service>(), iLocalEndpoint)
106 {
107 accept_connection();
108 }
109 tcp_packet_stream_server(i_async_task& aIoTask, const std::string& aLocalHostName, unsigned short aLocalPort, bool aSecure = false, protocol_family aProtocolFamily = IPv4) :
110 iIoTask(aIoTask),
111 iHandlerProxy(new handler_proxy(*this)),
112 iLocalHostName(aLocalHostName),
113 iLocalPort(aLocalPort),
114 iSecure(aSecure),
115 iProtocolFamily(aProtocolFamily & IPv4 ? protocol_type::v4() : protocol_type::v6()),
116 iLocalEndpoint(resolve(aIoTask, iLocalHostName, iLocalPort, iProtocolFamily)),
117 iAcceptor(aIoTask.io_service().native_object<boost::asio::io_service>(), iLocalEndpoint)
118 {
119 accept_connection();
120 }
122 {
124 for (typename stream_list::iterator i = iStreamList.begin(); i != iStreamList.end(); ++i)
125 *i = nullptr;
126 iStreamList.clear();
127 iAcceptor.close();
128 }
129
130 // operations
131 public:
132 unsigned short local_port() const
133 {
134 return iLocalPort;
135 }
136 packet_stream_pointer take_ownership(packet_stream_type& aStream)
137 {
138 for (typename stream_list::iterator i = iStreamList.begin(); i != iStreamList.end(); ++i)
139 if (&**i == &aStream)
140 {
141 packet_stream_pointer found{ std::move(*i) };
142 iStreamList.erase(i);
143 return std::move(found);
144 }
145 throw stream_not_found();
146 }
147
148 // implementation
149 private:
150 // own
151 static endpoint_type resolve(async_task& aIoTask, const std::string& aHostname, unsigned short aPort, protocol_type aProtocolFamily)
152 {
153 resolver_type resolver(aIoTask.io_service().native_object());
154 boost::system::error_code ec;
155 typename resolver_type::iterator result = resolver.resolve(resolver_type::query(aHostname, std::to_string(aPort), ec));
156 if (!ec)
157 {
158 for (typename resolver_type::iterator i = result; i != resolver_type::iterator(); ++i)
159 {
160 endpoint_type endpoint = *i;
161 if (endpoint.protocol() == aProtocolFamily)
162 return endpoint;
163 }
164 return *result;
165 }
166 throw failed_to_resolve_local_host();
167 }
168 void accept_connection()
169 {
170 if (iAcceptingStream != nullptr)
171 return;
172 iAcceptingStream = std::make_unique<packet_stream_type>(iIoTask, iSecure, iLocalEndpoint.protocol() == protocol_type::v4() ? IPv4 : IPv6);
173 auto acceptingStream = &*iAcceptingStream;
174 iSink += iAcceptingStream->connection_closed([this, acceptingStream]()
175 {
176 if (is_alive())
177 {
178 for (typename stream_list::iterator i = iStreamList.begin(); i != iStreamList.end(); ++i)
179 if (&**i == acceptingStream)
180 {
181 packet_stream_pointer keepObjectAlive{ std::move(*i) };
182 iStreamList.erase(i);
183 PacketStreamRemoved.trigger(*acceptingStream);
184 break;
185 }
186 }
187 else
188 PacketStreamRemoved.trigger(*acceptingStream);
189 });
190
191 iAcceptingStream->connection().open(true);
192 iAcceptor.async_accept(iAcceptingStream->connection().socket(), boost::bind(&handler_proxy::operator(), iHandlerProxy, boost::asio::placeholders::error));
193 }
194 void handle_accept(const boost::system::error_code& aError)
195 {
196 if (!aError)
197 {
198 iAcceptingStream->connection().server_accept();
199 iStreamList.push_back(std::move(iAcceptingStream));
200 PacketStreamAdded.trigger(*iStreamList.back());
201 accept_connection();
202 }
203 else
204 FailedToAcceptPacketStream.trigger(aError);
205 }
206
207 // attributes
208 private:
209 i_async_task& iIoTask;
210 std::shared_ptr<handler_proxy> iHandlerProxy;
211 std::string iLocalHostName;
212 unsigned short iLocalPort;
213 bool iSecure;
214 protocol_type iProtocolFamily;
215 endpoint_type iLocalEndpoint;
216 acceptor_type iAcceptor;
217 packet_stream_pointer iAcceptingStream;
218 stream_list iStreamList;
219 sink iSink;
220 };
221
223}
neolib::i_async_service & io_service() override
virtual void * native_object()=0
void set_destroying() override
Definition lifetime.hpp:165
bool is_alive() const final
Definition lifetime.hpp:139
packet_stream< packet_type, protocol_type > packet_stream_type
tcp_packet_stream_server(i_async_task &aIoTask, unsigned short aLocalPort, bool aSecure=false, protocol_family aProtocolFamily=IPv4)
define_event(PacketStreamAdded, packet_stream_added, packet_stream_type &) define_event(PacketStreamRemoved
tcp_packet_stream_server(i_async_task &aIoTask, const std::string &aLocalHostName, unsigned short aLocalPort, bool aSecure=false, protocol_family aProtocolFamily=IPv4)
packet_stream_pointer take_ownership(packet_stream_type &aStream)
packet_stream_type &define_event(FailedToAcceptPacketStream, failed_to_accept_packet_stream, const boost::system::error_code &) private typedef std::vector< packet_stream_pointer > stream_list
boost::asio::ip::tcp tcp_protocol
tcp_packet_stream_server< string_packet > tcp_string_packet_stream_server
protocol_family
Definition resolver.hpp:52
Definition plf_hive.h:79
#define define_event(name, declName,...)
Definition event.hpp:200