void ReadAndProcessPong() { int bytesRead = 0; EndPoint responseEndpoint = AnyAddressEndpoint; try { bytesRead = MainSocket.ReceiveFrom(Buffer, ref responseEndpoint); } catch (SocketException e) { if (e.ErrorCode == (int)SocketError.ConnectionReset) { LogWarning("ConnectionReset"); } else { LogWarning("Exception while reading from socket: " + e.ToString()); } return; } string pongIdentifier = System.Text.Encoding.ASCII.GetString(Buffer, 0, bytesRead); if (PingRecords.ContainsKey(pongIdentifier)) { PingRecord rec = PingRecords[pongIdentifier]; rec.Stopwatch.Stop(); PingRecords.Remove(pongIdentifier); int pingTime = (int)rec.Stopwatch.ElapsedMilliseconds; // statistics if (pingTime < MinPingTime) { MinPingTime = pingTime; } if (pingTime > MaxPingTime) { MaxPingTime = pingTime; } PingTimeSum += pingTime; PongRcvCount++; Log("Received pong from " + responseEndpoint + " in " + pingTime + " ms"); } else { // probably outdated pong or other rabbish } }
private async Task WriteToDatabase(string url, bool success, string errorMessage = null) { var dbContext = new DbContextFactory().CreateDbContext(); var record = new PingRecord { DateTime = DateTime.UtcNow, IsOk = success, Url = url, Description = errorMessage }; await dbContext.PingRecords.AddAsync(record); await dbContext.SaveChangesAsync(); }
/// <summary> /// The client tests if the server if up ... this call generally occurs on connection on an existing account! /// </summary> public void Ping() { try { DateTime now = DateTime.Now; Debug($"Ping from '{Context.ConnectionId}'"); using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext()) { // receive the ping from the client PingRecord existingPing = database._Ping.Find(Context.ConnectionId); if (existingPing != null) { existingPing.Date = now; } else { database._Ping.Add(new PingRecord { ConnectionId = Context.ConnectionId }); } // update the last connection time of the client ConnectionRecord currentConnection = database._Connection.Find(Context.ConnectionId); if (currentConnection != null) { currentConnection.ConnectionLast = now; } database.SaveChanges(); } } catch (System.Exception ex) { Exception($"An exception occurs on pinging of the connection '{Context.ConnectionId}'", ex); Warn("This exception is ignored ... may be the connection was previously deleted or disconnected!"); } }
/// <summary> /// Check if the given user is already connected through hub /// </summary> /// <param name="userId"></param> /// <returns></returns> public static bool IsAlreadyConnected(int userId) { // the user exists, check if it's already connected // In case of reloading page, the connection can't be disconnected as quick as expected ... IHubContext hub = GlobalHost.ConnectionManager.GetHubContext <DatabaseHub>(); if (hub == null) { // no hub ... disconnect the user and go to the index page Common.Logger.LoggerManager.Instance.Info(MODULE, $"Cleaning up all connections for the user {userId} ..."); using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext()) { ConnectionRecord currentConnection = database._Connection.FirstOrDefault(c => c.UserId == userId && c.Allow); while (currentConnection != null) { Common.Logger.LoggerManager.Instance.Debug(MODULE, $"Connection {currentConnection} removed ..."); try { database._Connection.Remove(currentConnection); } catch { } currentConnection = database._Connection.FirstOrDefault(c => c.UserId == userId && c.Allow); } database.SaveChanges(); } return(false); } // DatabaseCommonContext is frequently open/close here to clean up the cache of the database (else the ping record is never updated) ... bool alreadyConnected = true; DateTime pingDate = DateTime.Now; int count = 0; while (count < ConfigurationManager.ConnectionMaxWaiting && alreadyConnected) { count++; ConnectionRecord currentConnection = null; using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext()) currentConnection = database._Connection.FirstOrDefault(c => c.UserId == userId && c.Allow); if (currentConnection != null && count < ConfigurationManager.ConnectionMaxWaiting) { // Ping the client and wait 1 secondes to check if the client responses if (count == 1) { Thread.Sleep(1000); Common.Logger.LoggerManager.Instance.Debug(MODULE, $"Ping to '{currentConnection.ConnectionId}'"); hub.Clients.Client(currentConnection.ConnectionId).ping(); } // Did the client answer to the ping ? PingRecord currentPing = null; using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext()) currentPing = database._Ping.Find(currentConnection.ConnectionId); // The client has answered to the ping ... So, it already exists if (currentPing != null && DateTime.Compare(currentPing.Date, pingDate) >= 0) { break; } // The client didn't answer ... wait a few more second if (count > 1) { Thread.Sleep(1000); } } else if (currentConnection != null) { // The max seconds has expired ... it means that no client is already connected ... disconnect it alreadyConnected = false; try { hub.Clients.Client(currentConnection.ConnectionId).stop(); Common.Logger.LoggerManager.Instance.Info(MODULE, $"The connection '{currentConnection.ConnectionId}' is disconnected"); } catch (System.Exception ex) { Common.Logger.LoggerManager.Instance.Exception(MODULE, $"(Warning) Unable to disconnect '{currentConnection.ConnectionId}' due to an exception", ex); } using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext()) { currentConnection = database._Connection.Find(currentConnection.ConnectionId); currentConnection.Allow = false; database.SaveChanges(); } } else { alreadyConnected = false; Common.Logger.LoggerManager.Instance.Info(MODULE, $"No connection already existing or the previous connection is disconnected ..."); } } if (alreadyConnected) { Common.Logger.LoggerManager.Instance.Debug(MODULE, $"The user '{userId}' is already connected on another support"); return(true); } return(false); }