void KristalliProtocolModule::Update(f64 frametime) { // Update method for multiconnection. if (!serverConnection_map_.isEmpty()) connectionArrayUpdate(); // Pulls all new inbound network messages and calls the message handler we've registered // for each of them. if (serverConnection) serverConnection->Process(); // Note: Calling the above serverConnection->Process() may set serverConnection to null if the connection gets disconnected. // Therefore, in the code below, we cannot assume serverConnection is non-null, and must check it again. // Our client->server connection is never kept half-open. // That is, at the moment the server write-closes the connection, we also write-close the connection. // Check here if the server has write-closed, and also write-close our end if so. if (serverConnection && !serverConnection->IsReadOpen() && serverConnection->IsWriteOpen()) serverConnection->Disconnect(0); // Process server incoming connections & messages if server up if (server) { server->Process(); // In Tundra, we *never* keep half-open server->client connections alive. // (the usual case would be to wait for a file transfer to complete, but Tundra messaging mechanism doesn't use that). // So, bidirectionally close all half-open connections. NetworkServer::ConnectionMap connections = server->GetConnections(); for(NetworkServer::ConnectionMap::iterator iter = connections.begin(); iter != connections.end(); ++iter) if (!iter->second->IsReadOpen() && iter->second->IsWriteOpen()) iter->second->Disconnect(0); } if ((!serverConnection || serverConnection->GetConnectionState() == ConnectionClosed || serverConnection->GetConnectionState() == ConnectionPending) && serverIp.length() != 0) { const int cReconnectTimeout = 5 * 1000.f; if (reconnectTimer.Test()) { if (reconnectAttempts) { PerformConnection(); --reconnectAttempts; } else { LogInfo("Failed to connect to " + serverIp + ":" + ToString(serverPort)); // If connection fails we just ignore it. Client has no use for information if initial connection failed. //framework_->GetEventManager()->SendEvent(networkEventCategory, Events::CONNECTION_FAILED, 0); reconnectTimer.Stop(); serverIp = ""; } } else if (!reconnectTimer.Enabled()) reconnectTimer.StartMSecs(cReconnectTimeout); } // If connection was made, enable a larger number of reconnection attempts in case it gets lost if (serverConnection && serverConnection->GetConnectionState() == ConnectionOK) { // save succesfully established connection to messageconnection array with all connection properties. for (unsigned short connection = 0;; connection++) { if (!serverConnection_map_.contains(connection)) { // Associative QMap stores all items sorted by Key. If array has one item terminated, // we fill it with next succesfull connection. Same is done in client. serverConnection_map_.insert(connection, serverConnection); serverIp_list_.insert(connection,serverIp); serverPort_list_.insert(connection,serverPort); serverTransport_list_.insert(connection, serverTransport); reconnectAttempts_list_.insert(connection, cReconnectAttempts); reconnectTimer.Reset(); reconnectTimer_list_.insert(connection,reconnectTimer); serverConnection = 0; serverIp = ""; serverPort = 0; break; } } } RESETPROFILER; }
void KristalliProtocolModule::Update(f64 /*frametime*/) { // Pulls all new inbound network messages and calls the message handler we've registered // for each of them. if (serverConnection) { PROFILE(KristalliProtocolModule_kNet_client_Process); serverConnection->Process(); } // Note: Calling the above serverConnection->Process() may set serverConnection to null if the connection gets disconnected. // Therefore, in the code below, we cannot assume serverConnection is non-null, and must check it again. // Our client->server connection is never kept half-open. // That is, at the moment the server write-closes the connection, we also write-close the connection. // Check here if the server has write-closed, and also write-close our end if so. if (serverConnection && !serverConnection->IsReadOpen() && serverConnection->IsWriteOpen()) serverConnection->Disconnect(0); // Process server incoming connections & messages if server up if (server) { PROFILE(KristalliProtocolModule_kNet_server_Process); server->Process(); // In Tundra, we *never* keep half-open server->client connections alive. // (the usual case would be to wait for a file transfer to complete, but Tundra messaging mechanism doesn't use that). // So, bidirectionally close all half-open connections. NetworkServer::ConnectionMap connections = server->GetConnections(); for(NetworkServer::ConnectionMap::iterator iter = connections.begin(); iter != connections.end(); ++iter) if (!iter->second->IsReadOpen() && iter->second->IsWriteOpen()) iter->second->Disconnect(0); } if ((!serverConnection || serverConnection->GetConnectionState() == ConnectionClosed || serverConnection->GetConnectionState() == ConnectionPending) && serverIp.length() != 0) { const int cReconnectTimeout = 5 * 1000.f; if (reconnectTimer.Test()) { if (reconnectAttempts) { PerformConnection(); --reconnectAttempts; } else { ::LogInfo(QString("Failed to connect to %1:%2").arg(serverIp.c_str()).arg(serverPort)); emit ConnectionAttemptFailed(); reconnectTimer.Stop(); serverIp = ""; } } else if (!reconnectTimer.Enabled()) reconnectTimer.StartMSecs(cReconnectTimeout); } // If connection was made, enable a larger number of reconnection attempts in case it gets lost if (serverConnection && serverConnection->GetConnectionState() == ConnectionOK) reconnectAttempts = cReconnectAttempts; }