| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- /* Copyright The kNet Project.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License. */
- #pragma once
- /** @file NetworkServer.h
- @brief The NetworkServer class. The main class for hosting a kNet server. */
- #include <list>
- #include "kNetBuildConfig.h"
- #include "SharedPtr.h"
- #include "Socket.h"
- #include "MessageConnection.h"
- #include "Datagram.h"
- #include "INetworkServerListener.h"
- #include "Lockable.h"
- namespace kNet
- {
- class Network;
- /// Manages all low-level networking required in maintaining a network server and keeps
- /// track of all currently established connections.
- /// NetworkServer has the
- class NetworkServer : public RefCountable
- {
- public:
- /// When destroyed, the NetworkServer closes all the server connections it has.
- ~NetworkServer();
- /// Enters a stand-alone processing loop that manages incoming connections until server is shut down.
- void RunModalServer();
- /// Enables or disables whether new connection attempts are allowed.
- void SetAcceptNewConnections(bool acceptNewConnections);
- // Returns whether this server is handling new connection attempts.
- bool AcceptsNewConnections() const { return acceptNewConnections; }
- /// Enables or disables whether rejected connection attempts are messaged back to the client (UDP only).
- /// i.e. whether to message "Connection rejected" back to the peer.
- void SetStealthMode(bool stealthModeEnabled);
- /// Handles all new connection attempts and pulls in new messages from all existing connections.
- /// Periodically call this function to update the NetworkServer object.
- void Process();
- /// Broadcasts the given message to all currently active connections, except for the single 'exclude' connection.
- /// If exclude is 0, all clients will receive the message.
- /// @param msg The message to send.
- /// @param exclude The network connection to exclude from the recipient list. All other clients connected to this
- /// server will get the message. This parameter is useful when you are implementing a server that relays messages
- /// between clients and want to avoid "echoing" the original message back to the client who sent it.
- void BroadcastMessage(const NetworkMessage &msg, MessageConnection *exclude = 0);
- /// Creates a NetworkMessage structure with the given data and broadcasts it to all currently active connections,
- /// except to the given excluded connection.
- void BroadcastMessage(unsigned long id, bool reliable, bool inOrder, unsigned long priority,
- unsigned long contentID, const char *data, size_t numBytes,
- MessageConnection *exclude = 0);
- template<typename SerializableData>
- void BroadcastStruct(const SerializableData &data, unsigned long id, bool inOrder,
- bool reliable, unsigned long priority, unsigned long contentID = 0, MessageConnection *exclude = 0);
- template<typename SerializableMessage>
- void Broadcast(const SerializableMessage &data, unsigned long contentID = 0, MessageConnection *exclude = 0);
- /// Sends the given message to the given destination.
- void SendMessage(const NetworkMessage &msg, MessageConnection &destination);
- /// Starts a benign disconnection procedure for all clients (write-closes each connection).
- /// Also calls SetAcceptNewConnections(false), since this function is intended to be used when the server is going down.
- /// It can take an indefinite time for the connections to bidirectionally close, since it is up to the individual
- /// clients to write-close their end of the connections. This function returns immediately.
- void DisconnectAllClients();
-
- /// Forcibly closes down the server. Calls SetAcceptNewConnections(false) so that no new connections are accepted.
- /// @param disconnectWaitMilliseconds If >0, this function calls DisconnectAllClients() and waits for the given amount
- /// of time until calling Close() on each client connection. If 0, MessageConnection::Close(0) will be immediately
- /// called on each client. In that case, this function returns immediately and all active clients will be left
- /// to time out at their end. Calling this function does not guarantee that all outbound data will be received
- /// by the peers.
- void Close(int disconnectWaitMilliseconds);
-
- /// Forcibly erases the given connection from the active connection list. The client will be left to time out.
- void ConnectionClosed(MessageConnection *connection);
- /// Returns all the sockets this server is listening on.
- std::vector<Socket *> &ListenSockets();
- typedef std::map<EndPoint, Ptr(MessageConnection)> ConnectionMap;
- /// Returns all the currently tracked connections.
- ConnectionMap GetConnections();
- /// Returns the number of currently active connections. A connection is active if it is at least read- or write-open.
- int NumConnections() const;
- /// Returns a one-liner textual summary of this server.
- std::string ToString() const;
- private:
- /// Private ctor - NetworkServer instances are created by the Network class.
- NetworkServer(Network *owner, std::vector<Socket *> listenSockets);
- /// We store possibly multiple listening sockets so that the server
- /// can listen on several sockets (UDP or TCP) at once, making it
- /// possible for clients to bypass firewalls and/or mix UDP and TCP use.
- std::vector<Socket *> listenSockets;
- /// The list of active client connections.
- Lockable<ConnectionMap> clients;
- /// The Network object this NetworkServer was spawned from.
- Network *owner;
- /// Stores the thread that manages the background processing of this server. The same thread can manage multiple
- /// connections and servers, and not just this one.
- NetworkWorkerThread *workerThread; // [set and read only by worker thread]
- #ifdef KNET_THREAD_CHECKING_ENABLED
- /// In debug mode, we track and enforce thread safety constraints through this ID.
- ThreadId workerThreadId; // [set by worker thread on thread startup, read by both main and worker thread]
- #endif
- /// If true, new connection attempts are processed. Otherwise, just discard all connection packets.
- bool acceptNewConnections;
- INetworkServerListener *networkServerListener;
- /// Sets the worker thread object that will handle this server.
- void SetWorkerThread(NetworkWorkerThread *thread); // [main thread]
- NetworkWorkerThread *WorkerThread() const { return workerThread; }
- /// If the server is running in UDP mode, the listenSocket is the socket that receives all application data.
- /// This function pulls all new data from the socket and sends it to MessageConnection instances for deserialization and processing.
- void ReadUDPSocketData(Socket *listenSocket); // [worker thread]
- void RegisterServerListener(INetworkServerListener *listener);
- /// Shuts down all listen sockets used by this server.
- /// This function is to be called only at destruction time when no network communication is being performed anymore.
- void CloseSockets();
- void CleanupDeadConnections();
- Socket *AcceptConnections(Socket *listenSocket);
- struct ConnectionAttemptDescriptor
- {
- Socket *listenSocket;
- EndPoint peer;
- Datagram data;
- };
- WaitFreeQueue<ConnectionAttemptDescriptor> udpConnectionAttempts;
- /// Called from the network worker thread.
- void EnqueueNewUDPConnectionAttempt(Socket *listenSocket, const EndPoint &endPoint, const char *data, size_t numBytes);
- bool ProcessNewUDPConnectionAttempt(Socket *listenSocket, const EndPoint &endPoint, const char *data, size_t numBytes);
- friend class Network;
- friend class NetworkWorkerThread;
- };
- template<typename SerializableData>
- void NetworkServer::BroadcastStruct(const SerializableData &data, unsigned long id, bool inOrder,
- bool reliable, unsigned long priority, unsigned long contentID, MessageConnection *exclude)
- {
- PolledTimer timer;
- Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
- if (timer.MSecsElapsed() >= 50.f)
- {
- KNET_LOG(LogWaits, "NetworkServer::BroadcastMessage: Accessing the connection list took %f msecs.",
- timer.MSecsElapsed());
- }
- const size_t dataSize = data.Size();
- for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
- {
- MessageConnection *connection = iter->second;
- assert(connection);
- if (connection == exclude || !connection->IsWriteOpen())
- continue;
- NetworkMessage *msg = connection->StartNewMessage(id, dataSize);
- if (dataSize > 0)
- {
- DataSerializer mb(msg->data, dataSize);
- data.SerializeTo(mb);
- assert(mb.BytesFilled() == dataSize); // The SerializableData::Size() estimate must be exact!
- }
- msg->id = id;
- msg->reliable = reliable;
- msg->inOrder = inOrder;
- msg->priority = priority;
- msg->contentID = contentID;
- #ifdef KNET_NETWORK_PROFILING
- char str[512];
- sprintf(str, "%s (%u)", SerializableData::Name(), (unsigned int)id);
- msg->profilerName = str;
- #endif
- connection->EndAndQueueMessage(msg);
- }
- }
- template<typename SerializableMessage>
- void NetworkServer::Broadcast(const SerializableMessage &data, unsigned long contentID, MessageConnection *exclude)
- {
- BroadcastStruct(data, SerializableMessage::messageID, data.inOrder, data.reliable, data.priority, contentID, exclude);
- }
- } // ~kNet
|