internal static void NC_MISC_S2SCONNECTION_REQ(NetworkMessage message, NetworkConnection connection) { var from = message.ReadByte(); var to = message.ReadByte(); var worldNumber = message.ReadByte(); var worldName = message.ReadString(20); var unused = message.ReadByte(); var ip = message.ReadString(16); var port = message.ReadUInt16(); var key = message.ReadUInt16(); if (key != from + to) { SocketLog.Write(SocketLogLevel.Warning, "Invalid key used with S2S connection."); connection.Disconnect(); return; } if ((NetworkConnectionType)@from != NetworkConnectionType.NCT_WORLDMANAGER) { return; } if (ServerMain.Worlds.Exists(world => world.Connection == connection || world.Number == worldNumber)) { return; } ServerMain.Worlds.Add(new World(connection, worldName, worldNumber, ip, port)); new PROTO_NC_MISC_S2SCONNECTION_ACK().Send(connection); }
protected void Log(string info, LogLevel logLevel) { // 必须要加锁保证Log文件写时不被占用 lock (LoggerLock) { SocketLog?.Invoke(this, new SocketLogEventArgs(info, logLevel)); } }
/// <summary> /// Invokes the message handler. /// </summary> public static void Invoke(NetworkMessageHandlerMethod method, NetworkMessage message, NetworkConnection connection) { if (method == null || !connection.IsConnected) { return; } SocketLog.Write(SocketLogLevel.Debug, $"Calling handler for {message.Command}"); var stopwatch = new Stopwatch(); stopwatch.Start(); var cancelSource = new CancellationTokenSource(); var token = cancelSource.Token; var task = HandlerFactory.StartNew(() => { method.Invoke(message, connection); token.ThrowIfCancellationRequested(); }, token); RunningHandlers.TryAdd(task.Id, task); try { if (!task.Wait(MaxTaskRuntime * 1000, token)) { cancelSource.Cancel(); } } catch (AggregateException ex) { foreach (var e in ex.Flatten().InnerExceptions) { SocketLog.Write(SocketLogLevel.Exception, $"Unhandled exception: {e.Message} - {e.StackTrace}"); } connection.Disconnect(); } catch (OperationCanceledException) { connection.Disconnect(); } finally { stopwatch.Stop(); RunningHandlers.TryRemove(task.Id, out var unused); cancelSource.Dispose(); Object.Destroy(message); SocketLog.Write(SocketLogLevel.Debug, $"Handler took {stopwatch.ElapsedMilliseconds}ms to complete."); } }
/// <summary> /// Places the server in the listening state. /// </summary> /// <param name="ipAddress">The IP address to listen for connection on.</param> /// <param name="port">The port to listen for connections on.</param> /// <param name="backlog">The maximum number of pending connections in the queue.</param> public void Listen(string ipAddress, ushort port, int backlog = BacklogSize) { if (!IPAddress.TryParse(ipAddress, out var address)) { SocketLog.Write(SocketLogLevel.Exception, $"The IPAddress {ipAddress} is invalid."); return; } _socket.Bind(new IPEndPoint(address, port)); _socket.Listen(backlog); _socket.BeginAccept(AcceptConnection, _socket); }
internal static void NC_USER_CLIENT_VERSION_CHECK_REQ(NetworkMessage message, NetworkConnection connection) { var versionKey = message.ReadString(64); if (versionKey != LoginConfiguration.Instance.ClientVersion && ServerMain.LoginConfig.CheckVersion) { SocketLog.Write(SocketLogLevel.Exception, $"Wrong version key used - {versionKey}"); new PROTO_NC_USER_CLIENT_WRONGVERSION_CHECK_ACK().Send(connection); return; } new PROTO_NC_USER_CLIENT_RIGHTVERSION_CHECK_ACK((byte)XTrapKey.Length, XTrapKey).Send(connection); }
internal static void NC_USER_WILLLOGIN_ACK(NetworkMessage message, NetworkConnection connection) { var guid = message.ReadString(32); var ok = message.ReadBoolean(); var transfer = ServerMain.Transfers.First(t => t.Guid == guid); ServerMain.Transfers.RemoveSafe(transfer); if (!ok || !transfer) { SocketLog.Write(SocketLogLevel.Exception, $"Process transfer failed for - {transfer}"); new PROTO_NC_USER_LOGINFAIL_ACK(0x49).Send(transfer?.Connection); return; } ServerMain.CachedAccounts.AddSafe(guid, transfer.Account); new PROTO_NC_USER_WORLDSELECT_ACK(transfer.World, guid).Send(transfer.Connection); Object.Destroy(transfer); }
/// <summary> /// Accepts a pending connection. /// </summary> /// <param name="e">The status of the operation.</param> private void AcceptConnection(IAsyncResult e) { if (e.AsyncState == null) { SocketLog.Write(SocketLogLevel.Exception, "NetworkServer::AcceptConnection : AsyncState is null"); return; } var serverSocket = (Socket)e.AsyncState; var clientSocket = serverSocket.EndAccept(e); if (clientSocket != null) { var connection = new NetworkConnection(this, clientSocket, _connectionType); if (connection.IsConnected) { Connections.Add(connection); } } // Begin accepting connections again. serverSocket.BeginAccept(AcceptConnection, serverSocket); }
internal static void NC_USER_US_LOGIN_REQ(NetworkMessage message, NetworkConnection connection) { var userName = message.ReadString(260); var password = message.ReadString(36); AccountService.Login(userName, password, out var userNo, out var blocked, out var canLogin); if (userNo == -1) { SocketLog.Write(SocketLogLevel.Warning, $"[{connection}] Invalid credentials"); new PROTO_NC_USER_LOGINFAIL_ACK(0x45).Send(connection); new PROTO_NC_LOG_USER_LOGINFAIL(userName, password, connection.GetRemoteIP, 0x45).Send(ServerMain.GameLogServer); return; } if (blocked) { SocketLog.Write(SocketLogLevel.Warning, $"[{connection}] Logging in while banned"); new PROTO_NC_USER_LOGINFAIL_ACK(0x47).Send(connection); new PROTO_NC_LOG_USER_LOGINFAIL(userName, password, connection.GetRemoteIP, 0x47).Send(ServerMain.GameLogServer); return; } if (!canLogin) { SocketLog.Write(SocketLogLevel.Warning, $"[{connection}] Logging in during maintenance"); new PROTO_NC_USER_LOGINFAIL_ACK(0x48).Send(connection); new PROTO_NC_LOG_USER_LOGINFAIL(userName, password, connection.GetRemoteIP, 0x48).Send(ServerMain.GameLogServer); return; } connection.Account = new Account(userNo, userName); new PROTO_NC_USER_LOGIN_ACK(ServerMain.Worlds).Send(connection); }