Ejemplo n.º 1
0
		virtual void Install () override {
		
			auto & server=Server::Get();
			
			//	Get settings
			auto & data=server.Data();
			timeout=data.GetSetting(timeout_setting,timeout_default);
			keep_alive=data.GetSetting(keep_alive_setting,keep_alive_default);
			
			//	Install handler for incoming keep alives
			server.Router(
				recv::PacketID,
				recv::State
			)=[this] (PacketEvent event) mutable {	handler(std::move(event));	};
			
			//	Queue up timed callback
			server.Pool().Enqueue(
				get_callback_freq(),
				[this] () mutable {	callback();	}
			);
			
			//	Attach to connect/disconnect events
			//	to add/remove data structures
			server.OnConnect.Add([this] (SmartPointer<Client> client) mutable {
			
				lock.Execute([&] () mutable {	map.emplace(std::move(client),KeepAliveInfo());	});
			
			});
			server.OnDisconnect.Add([this] (SmartPointer<Client> client, const String &) mutable {
			
				lock.Execute([&] () mutable {	map.erase(client);	});
			
			});
		
		}
Ejemplo n.º 2
0
			void Complete (Vector<DNSRecord> results) {
			
				lock.Execute([&] () mutable {
				
					//	Fast fail
					if (failed) return;
				
					//	Try and add each result from this set
					//	to the aggregate set
					try {
					
						for (auto & result : results) this->results.Add(std::move(result));
					
					//	On exception, dutifully fail
					} catch (...) {
					
						promise.Fail(std::current_exception());
						
						failed=true;
					
					}
					
					//	If this is the last one in, complete
					//	the promise
					if ((++completed)==num) promise.Complete(std::move(this->results));
				
				});
			
			}
Ejemplo n.º 3
0
			void Fail (std::exception_ptr ex) noexcept {
			
				lock.Execute([&] () mutable {
				
					promise.Fail(std::move(ex));
					
					failed=true;
				
				});
			
			}
Ejemplo n.º 4
0
		//	Handles incoming packets
		void handler (PacketEvent event) {
		
			auto & packet=event.Data.Get<recv>();
			
			//	Check the ID, if it's zero then
			//	it's a client-initiated keep alive
			//	and we just reply in kind
			if (packet.KeepAliveID==0) {
			
				send reply;
				reply.KeepAliveID=0;
				
				event.From->Send(reply);
			
			//	Otherwise we have to check to make
			//	sure this is the right ID etc.
			} else {
			
				UInt64 elapsed;
				if (lock.Execute([&] () mutable {
				
					//	Look up data about this
					//	client
					auto iter=map.find(event.From);
					//	If the client's data can't be
					//	found, just stop processing
					if (iter==map.end()) return false;
					
					auto & data=iter->second;
					
					//	Stop the timer at once
					elapsed=data.Latency.ElapsedMilliseconds();
					
					//	If we're not actually
					//	waiting for a keep alive
					//	from this client, or this
					//	client sent the wrong ID,
					//	we kill them with a protocol
					//	error
					if (!(
						data.Waiting &&
						(data.ID==packet.KeepAliveID)
					)) {
					
						event.From->Disconnect(protocol_error);
						
						return false;
					
					}
					
					//	Everything is good, update
					//	the client's latency
					event.From->Ping=elapsed;
					//	We're no longer waiting
					data.Waiting=false;
					
					return true;
					
				})) {
				
					//	Log if applicable
					auto & server=Server::Get();
					if (server.IsVerbose(debug_key)) server.WriteLog(
						String::Format(
							log_ping,
							event.From->IP(),
							event.From->Port(),
							elapsed
						),
						Service::LogType::Debug
					);
				
				}
			
			}
		
		}
Ejemplo n.º 5
0
		//	Handles timed callbacks
		void callback () {
		
			auto & server=Server::Get();
		
			try {
				
				//	Cache whether or not we're doing
				//	verbose logging
				bool is_verbose=server.IsVerbose(debug_key);
			
				//	Loop for all clients
				for (auto & client : server.Clients) {
				
					//	Determine how long this client has been
					//	inactive
					auto inactive=client->Inactive();
					
					//	Did the client time out?
					bool timed_out=inactive>timeout;
					
					//	Debug logging if applicable
					if (is_verbose) server.WriteLog(
						String::Format(
							log_inactive,
							client->IP(),
							client->Port(),
							inactive,
							timed_out ? log_action_terminate : log_action_keep
						),
						Service::LogType::Debug
					);
					
					//	Kill if client has timed out
					if (timed_out) {
					
						client->Disconnect(
							String::Format(
								::timed_out,
								timeout,
								inactive
							)
						);
					
					//	Send them a ping, but only if they're
					//	in the correct state
					} else if (client->GetState()==ProtocolState::Play) {
					
						//	Generate a random ID that isn't zero
						//	(since zero is reserved for the client's
						//	use)
						auto id=dist(gen);
						if (id==0) ++id;
						
						lock.Execute([&] () mutable {
						
							//	Look up client's data
							auto iter=map.find(client);
							//	If the data could not be found,
							//	just abort
							if (iter==map.end()) return;
							
							auto & data=iter->second;
							
							//	Are we still waiting on a previous
							//	ping?
							if (data.Waiting) {
							
								//	Kill the client
								
								client->Disconnect(
									String::Format(
										ping_timed_out,
										data.Latency.ElapsedMilliseconds()
									)
								);
								
								return;
								
							}
							
							//	Send a new keep alive
							send packet;
							packet.KeepAliveID=id;
							
							client->Send(packet);
							
							//	We're now waiting
							data.Waiting=true;
							data.ID=id;
						
						});
					
					}
				
				}
				
				//	Queue up next iteration
				server.Pool().Enqueue(
					get_callback_freq(),
					[this] () mutable {	callback();	}
				);
				
			} catch (...) {
			
				//	Panic
				try {	server.Panic(std::current_exception());	} catch (...) {	}
				
				throw;
			
			}
		
		}