public async Task ClientWebSocketChannelWriteAfterCloseTest() { var websocket = new ClientWebSocket(); websocket.Options.AddSubProtocol(WebSocketConstants.SubProtocols.Mqtt); var uri = new Uri("ws://" + IotHubName + ":" + Port + WebSocketConstants.UriSuffix); await websocket.ConnectAsync(uri, CancellationToken.None); clientWebSocketChannel = new ClientWebSocketChannel(null, websocket); var threadLoop = new SingleThreadEventLoop("MQTTExecutionThread", TimeSpan.FromSeconds(1)); await threadLoop.RegisterAsync(clientWebSocketChannel); await clientWebSocketChannel.CloseAsync(); // Test Write API try { await clientWebSocketChannel.WriteAndFlushAsync(Unpooled.Buffer()); Assert.Fail("Should have thrown ClosedChannelException"); } catch (AggregateException e) { var innerException = e.InnerException as ClosedChannelException; Assert.IsNotNull(innerException); } done = true; }
public void Setup() { _session = Substitute.For <ISession>(); _pipeline = Substitute.For <IChannelPipeline>(); _group = new SingleThreadEventLoop(); _serializationService = new MessageSerializationService(); _channel = Substitute.For <IChannel>(); _channel.Pipeline.Returns(_pipeline); _channel.RemoteAddress.Returns(new IPEndPoint(IPAddress.Loopback, 8003)); _channelHandlerContext = Substitute.For <IChannelHandlerContext>(); _channelHandlerContext.Channel.Returns(_channel); _handshakeService = Substitute.For <IHandshakeService>(); _handshakeService.Auth(Arg.Any <PublicKey>(), Arg.Any <EncryptionHandshake>()).Returns(_authPacket); _handshakeService.Ack(Arg.Any <EncryptionHandshake>(), Arg.Any <Packet>()).Returns(_ackPacket).AndDoes(ci => ci.Arg <EncryptionHandshake>().Secrets = NetTestVectors.BuildSecretsWithSameIngressAndEgress()); _handshakeService.When(s => s.Agree(Arg.Any <EncryptionHandshake>(), Arg.Any <Packet>())).Do(ci => ci.Arg <EncryptionHandshake>().Secrets = NetTestVectors.BuildSecretsWithSameIngressAndEgress()); _logger = NullLogManager.Instance; _session.RemoteNodeId.Returns(NetTestVectors.StaticKeyB.PublicKey); }
public async Task StartWithExistingSocket(StreamSocket socket) { try { Debug.WriteLine($"{nameof(PushClient)}: Starting with existing socket."); Socket = socket; if (_loopGroup != null) { await Shutdown().ConfigureAwait(false); } _loopGroup = new SingleThreadEventLoop(); var streamSocketChannel = new StreamSocketChannel(Socket); streamSocketChannel.Pipeline.AddLast(new FbnsPacketEncoder(), new FbnsPacketDecoder(), this); await _loopGroup.RegisterAsync(streamSocketChannel).ConfigureAwait(false); await SendPing().ConfigureAwait(false); await _context.Executor.Schedule(KeepAliveLoop, TimeSpan.FromSeconds(KEEP_ALIVE - 60)); } catch (TaskCanceledException) { // pass } catch (Exception e) { #if !DEBUG Crashes.TrackError(e); #endif await Shutdown().ConfigureAwait(false); } }
public async Task StartAsync(EndPoint endPoint) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug($"准备启动服务主机,监听地址:{endPoint}。"); } IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1); IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2 var bootstrap = new ServerBootstrap(); if (AppConfig.ServerOptions.Libuv) { var dispatcher = new DispatcherEventLoopGroup(); bossGroup = dispatcher; workerGroup = new WorkerEventLoopGroup(dispatcher); bootstrap.Channel <TcpServerChannel>(); } else { bossGroup = new MultithreadEventLoopGroup(1); workerGroup = new MultithreadEventLoopGroup(); bootstrap.Channel <TcpServerSocketChannel>(); } var workerGroup1 = new SingleThreadEventLoop(); bootstrap .Option(ChannelOption.SoBacklog, AppConfig.ServerOptions.SoBacklog) .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default) .Group(bossGroup, workerGroup) .ChildHandler(new ActionChannelInitializer <IChannel>(channel => { var pipeline = channel.Pipeline; pipeline.AddLast(new LengthFieldPrepender(4)); pipeline.AddLast(new LengthFieldBasedFrameDecoder(int.MaxValue, 0, 4, 0, 4)); pipeline.AddLast(workerGroup1, "HandlerAdapter", new TransportMessageChannelHandlerAdapter(_transportMessageDecoder)); pipeline.AddLast(workerGroup1, "ServerHandler", new ServerHandler(async(contenxt, message) => { var sender = new DotNettyServerMessageSender(_transportMessageEncoder, contenxt); await OnReceived(sender, message); }, _logger)); })); try { _channel = await bootstrap.BindAsync(endPoint); if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug($"服务主机启动成功,监听地址:{endPoint}。"); } } catch { _logger.LogError($"服务主机启动失败,监听地址:{endPoint}。 "); } }
public async Task ClientWebSocketChannelReadWithoutConnectTest() { var websocket = new ClientWebSocket(); clientWebSocketChannel = new ClientWebSocketChannel(null, websocket); var threadLoop = new SingleThreadEventLoop("MQTTExecutionThread", TimeSpan.FromSeconds(1)); await threadLoop.RegisterAsync(clientWebSocketChannel); clientWebSocketChannel.Read(); }
public async Task ClientWebSocketChannelWriteWithoutConnectTest() { var websocket = new ClientWebSocket(); clientWebSocketChannel = new ClientWebSocketChannel(null, websocket); var threadLoop = new SingleThreadEventLoop("MQTTExecutionThread", TimeSpan.FromSeconds(1)); await threadLoop.RegisterAsync(clientWebSocketChannel).ConfigureAwait(false); await clientWebSocketChannel.WriteAndFlushAsync(new ConnectPacket()).ConfigureAwait(false); }
public async Task CanCloseTheChannel() { var webSocket = Mock.Of <WebSocket>(ws => ws.State == WebSocketState.Open); var channel = new ServerWebSocketChannel(webSocket, Mock.Of <EndPoint>()); var loop = new SingleThreadEventLoop(); await loop.RegisterAsync(channel); await channel.CloseAsync(); Assert.False(channel.Active); Mock.Get(webSocket).Verify( ws => ws.CloseAsync(WebSocketCloseStatus.NormalClosure, It.IsAny <string>(), It.IsAny <CancellationToken>())); }
public async Task DoesNotCloseAnAlreadyClosedWebSocket() { var webSocket = Mock.Of <WebSocket>(ws => ws.State == WebSocketState.Open); var channel = new ServerWebSocketChannel(webSocket, Mock.Of <EndPoint>()); var loop = new SingleThreadEventLoop(); await loop.RegisterAsync(channel); Mock <WebSocket> wsMock = Mock.Get(webSocket); wsMock.Setup(ws => ws.State).Returns(WebSocketState.Closed); wsMock.Setup(ws => ws.CloseAsync(It.IsAny <WebSocketCloseStatus>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .Throws(new Exception("WebSocket.CloseAsync should not be called")); await channel.CloseAsync(); }
public async Task Shutdown() { if (_loopGroup != null) { Debug.WriteLine("Stopped pinging push server"); var loopGroup = _loopGroup; _loopGroup = null; try { await loopGroup.ShutdownGracefullyAsync(TimeSpan.FromSeconds(0.2), TimeSpan.FromSeconds(1)) .ConfigureAwait(false); } catch (Exception e) { #if !DEBUG Crashes.TrackError(e); #endif } } }
public async Task ClientWebSocketChannelReadAfterCloseTest() { var websocket = new ClientWebSocket(); websocket.Options.AddSubProtocol(WebSocketConstants.SubProtocols.Mqtt); var uri = new Uri("ws://" + IotHubName + ":" + Port + WebSocketConstants.UriSuffix); await websocket.ConnectAsync(uri, CancellationToken.None); var clientReadListener = new ReadListeningHandler(); var clientChannel = new ClientWebSocketChannel(null, websocket); clientChannel .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default) .Option(ChannelOption.AutoRead, true) .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator()) .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default); clientChannel.Pipeline.AddLast( clientReadListener); var threadLoop = new SingleThreadEventLoop("MQTTExecutionThread", TimeSpan.FromSeconds(1)); await threadLoop.RegisterAsync(clientChannel); await clientChannel.CloseAsync(); // Test Read API try { await clientReadListener.ReceiveAsync(DefaultTimeout); Assert.Fail("Should have thrown InvalidOperationException"); } catch (InvalidOperationException e) { Assert.IsTrue(e.Message.Contains("Channel is closed")); } done = true; }
private static void Main() { GlobalVersion = Assembly.GetExecutingAssembly().GetName().Version; JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = new List <JsonConverter> { new IPEndPointConverter() } }; var jsonlog = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "GameServer.json"); var logfile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "GameServer.log"); Log.Logger = new LoggerConfiguration() .WriteTo.File(new JsonFormatter(), jsonlog) .WriteTo.File(logfile) .WriteTo.Console(outputTemplate: "[{Level} {SourceContext}] {Message}{NewLine}{Exception}") .MinimumLevel.Verbose() .CreateLogger(); var Logger = Log.ForContext(Constants.SourceContextPropertyName, "-Initialiazor"); #if !DEBUG AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; #endif TaskScheduler.UnobservedTaskException += OnUnobservedTaskException; Logger.Information("============================================"); Logger.Information("Initializing GameServer build {ver}...", $"{GlobalVersion.Major}.{GlobalVersion.Major / 2 + GlobalVersion.Minor + GlobalVersion.Build + GlobalVersion.Revision}"); #if NEWIDS Logger.Information("Set mode NEWIDS"); #endif #if LATESTS4 Logger.Information("Set mode LATESTS4"); #endif Logger.Information("============================================"); Logger.Information("Initializing Database..."); AuthDatabase.Initialize(); GameDatabase.Initialize(); Logger.Information("============================================"); Logger.Information("Starting Serverinstances and ResourceCache..."); ItemIdGenerator.Initialize(); CharacterIdGenerator.Initialize(); DenyIdGenerator.Initialize(); var listenerThreads = new MultithreadEventLoopGroup(Config.Instance.ListenerThreads); var workerThreads = new MultithreadEventLoopGroup(Config.Instance.WorkerThreads); var workerThread = new SingleThreadEventLoop(); ChatServer.Initialize(new Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = workerThreads, WorkerThread = workerThread, #if DEBUG Logger = Logger, #endif }); RelayServer.Initialize(new Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = workerThreads, WorkerThread = workerThread, #if DEBUG Logger = Logger, #endif }); GameServer.Initialize(new Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = workerThreads, WorkerThread = workerThread, #if DEBUG Logger = Logger, #endif }); FillShop(); ChatServer.Instance.Listen(Config.Instance.ChatListener); RelayServer.Instance.Listen(Config.Instance.RelayListener, IPAddress.Parse(Config.Instance.IP), Config.Instance.RelayUdpPorts); GameServer.Instance.Listen(Config.Instance.Listener); Logger.Information("Serverinstances successfully started, ready for connections!"); Logger.Information("============================================\n"); Console.CancelKeyPress += OnCancelKeyPress; while (true) { var input = Console.ReadLine(); if (input == null) { break; } if (input.Equals("exit", StringComparison.InvariantCultureIgnoreCase) || input.Equals("quit", StringComparison.InvariantCultureIgnoreCase) || input.Equals("stop", StringComparison.InvariantCultureIgnoreCase)) { break; } var args = input.GetArgs(); if (args.Length == 0) { continue; } Task.Run(() => { if (!GameServer.Instance.CommandManager.Execute(null, args)) { Console.WriteLine("Unknown command"); } }); } Exit(); }
public SingleInstanceEventLoopGroup() { this.eventLoop = new SingleThreadEventLoop(); }
public async Task StartAsync() { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug($"准备启动服务主机,监听地址:{_tcpServerProperties.Host}:{_tcpServerProperties.Port}。"); } IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1); IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2 var tcpServiceEntryProvider = ServiceLocator.GetService <ITcpServiceEntryProvider>(); var workerGroup1 = new SingleThreadEventLoop(); var bootstrap = new ServerBootstrap(); bootstrap .Channel <TcpServerSocketChannel>() .ChildOption(ChannelOption.SoKeepalive, true) .Option(ChannelOption.SoBacklog, AppConfig.ServerOptions.SoBacklog) .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default) .Group(bossGroup, workerGroup) .ChildHandler(new ActionChannelInitializer <IChannel>(channel => { var pipeline = channel.Pipeline; pipeline.AddLast(new ConnectionChannelHandlerAdapter(_logger, ServiceLocator.GetService <IDeviceProvider>(), tcpServiceEntryProvider, _tcpServerProperties)); pipeline.AddLast(workerGroup1, "ServerHandler", new ServerHandler(_tcpServerProperties, _engine, _ruleWorkflow, _logger) ); switch (_tcpServerProperties.ParserType) { case PayloadParserType.Direct: { pipeline.AddLast(new LengthFieldPrepender(4)); pipeline.AddLast(new LengthFieldBasedFrameDecoder(int.MaxValue, 0, 4, 0, 4)); } break; case PayloadParserType.FixedLength: { if (_tcpServerProperties.ParserConfiguration != null && _tcpServerProperties.ParserConfiguration.ContainsKey("size")) { var configValue = _tcpServerProperties.ParserConfiguration["size"]; pipeline.AddLast(new FixedLengthFrameDecoder(int.Parse(configValue.ToString() ?? "0"))); } } break; case PayloadParserType.Delimited: { if (_tcpServerProperties.ParserConfiguration != null && _tcpServerProperties.ParserConfiguration.ContainsKey("delimited")) { var configValue = _tcpServerProperties.ParserConfiguration["delimited"]; var delimiter = Unpooled.CopiedBuffer(Encoding.Default.GetBytes(configValue.ToString() ?? "")); pipeline.AddLast(new DelimiterBasedFrameDecoder(int.MaxValue, true, delimiter)); } } break; } })) .Option(ChannelOption.SoBroadcast, true); try { _channel = await bootstrap.BindAsync(_tcpServerProperties.CreateSocketAddress()); if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug($"Tcp服务主机启动成功,监听地址:{_tcpServerProperties.Host}:{_tcpServerProperties.Port}。"); } } catch (Exception ex) { _logger.LogError($"Tcp服务主机启动失败,监听地址:{_tcpServerProperties.Host}:{_tcpServerProperties.Port}。 "); } }
private static void Main() { AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; TaskScheduler.UnobservedTaskException += OnUnobservedTaskException; GlobalVersion = Assembly.GetExecutingAssembly().GetName().Version; JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = new List <JsonConverter> { new IPEndPointConverter() } }; var jsonlog = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "GameServer.json"); var logfile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "GameServer.log"); Log.Logger = new LoggerConfiguration() .WriteTo.File(new JsonFormatter(), jsonlog) .WriteTo.File(logfile) .Enrich.With <ContextEnricher>() .Enrich.With <AccUserEnricher>() .WriteTo.Console( outputTemplate: "[{Level:u3}] |{SrcContext}| {AccUSpace:u3} | {Message}{NewLine}{Exception}") .MinimumLevel.Verbose() .CreateLogger(); var Logger = Log.ForContext(Constants.SourceContextPropertyName, "Initialiazor"); Logger.Information("============================================"); //Logger.Information("Initializing GameServer build {ver}...", // $"{GlobalVersion.Major}.{GlobalVersion.Major / 2 + GlobalVersion.Minor + GlobalVersion.Build + GlobalVersion.Revision}"); #if NEWIDS Logger.Information("Set mode NEWIDS"); #endif #if LATESTS4 Logger.Information("Set mode LATESTS4"); #endif Logger.Information("============================================"); Logger.Information("Initializing Database..."); AuthDatabase.Initialize(); GameDatabase.Initialize(); Logger.Information("============================================"); Logger.Information("Starting Serverinstances and ResourceCache..."); ItemIdGenerator.Initialize(); DenyIdGenerator.Initialize(); var listenerThreads = new MultithreadEventLoopGroup(Config.Instance.ListenerThreads); var workerThread = new SingleThreadEventLoop(); ChatServer.Initialize(new Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = new MultithreadEventLoopGroup(Config.Instance.WorkerThreads / 3), WorkerThread = workerThread }); RelayServer.Initialize(new Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = new MultithreadEventLoopGroup(Config.Instance.WorkerThreads / 3), WorkerThread = workerThread, }); GameServer.Initialize(new Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = new MultithreadEventLoopGroup(Config.Instance.WorkerThreads / 3), WorkerThread = workerThread }); FillShop(); ChatServer.Instance.Listen(Config.Instance.ChatListener); RelayServer.Instance.Listen(Config.Instance.RelayListener, IPAddress.Parse(Config.Instance.IP), Config.Instance.RelayUdpPorts); GameServer.Instance.Listen(Config.Instance.Listener); Log.Information("Starting Game API"); s_gameApiEventLoopGroup = new MultithreadEventLoopGroup(2); s_gameHost = new ServerBootstrap() .Group(s_gameApiEventLoopGroup) .Channel <TcpServerSocketChannel>() .Handler(new ActionChannelInitializer <IChannel>(ch => { })) .ChildHandler(new ActionChannelInitializer <IChannel>(ch => { ch.Pipeline.AddLast(new GameServerHandler()); })) .BindAsync(Config.Instance.FumbiAPI.EndPoint).GetAwaiter().GetResult(); if (Config.Instance.ACMode == 2) { Logger.Information("[BE] Activated"); } if (Config.Instance.ResCheck) { Logger.Information("[ResCheck] Activated : {0}", Config.Instance.ResHash); Logger.Information("[ResCheck_Red] Activated : {0}", Config.Instance.ResHash_red); Logger.Information("[ResCheck_Gold] Activated : {0}", Config.Instance.ResHash_gold); Logger.Information("[ResCheck_Blue] Activated : {0}", Config.Instance.ResHash_blue); Logger.Information("[ResCheck_Violet] Activated : {0}", Config.Instance.ResHash_violet); } Logger.Information("Waiting For Connections!"); Logger.Information("============================================"); Console.CancelKeyPress += OnCancelKeyPress; while (true) { var input = Console.ReadLine(); if (input == null) { break; } if (input.Equals("exit", StringComparison.InvariantCultureIgnoreCase) || input.Equals("quit", StringComparison.InvariantCultureIgnoreCase) || input.Equals("stop", StringComparison.InvariantCultureIgnoreCase)) { break; } var args = input.GetArgs(); if (args.Length == 0) { continue; } Task.Run(async() => { if (!await GameServer.Instance.CommandManager.Execute(null, args)) { CommandManager.Logger.Information("Unknown command"); } }); } Exit(); }
public async Task StartFresh() { try { Debug.WriteLine($"{nameof(PushClient)}: Starting fresh."); if (_loopGroup != null) { await Shutdown(); } _loopGroup = new SingleThreadEventLoop(); var connectPacket = new FbnsConnectPacket { Payload = await PayloadProcessor.BuildPayload(ConnectionData) }; Socket = new StreamSocket(); Socket.Control.KeepAlive = true; Socket.Control.NoDelay = true; if (await RequestBackgroundAccess()) { try { Socket.EnableTransferOwnership(_socketActivityTask.TaskId, SocketActivityConnectedStandbyAction.Wake); } catch (Exception connectedStandby) { Debug.WriteLine(connectedStandby); Debug.WriteLine($"{nameof(PushClient)}: Connected standby not available."); try { Socket.EnableTransferOwnership(_socketActivityTask.TaskId, SocketActivityConnectedStandbyAction.DoNotWake); } catch (Exception e) { #if !DEBUG Crashes.TrackError(e); #endif Debug.WriteLine(e); Debug.WriteLine($"{nameof(PushClient)}: Failed to transfer socket completely!"); await Shutdown().ConfigureAwait(false); return; } } } await Socket.ConnectAsync(new HostName(HOST_NAME), "443", SocketProtectionLevel.Tls12); var streamSocketChannel = new StreamSocketChannel(Socket); streamSocketChannel.Pipeline.AddLast(new FbnsPacketEncoder(), new FbnsPacketDecoder(), this); await _loopGroup.RegisterAsync(streamSocketChannel).ConfigureAwait(false); await streamSocketChannel.WriteAndFlushAsync(connectPacket).ConfigureAwait(false); } catch (Exception e) { #if !DEBUG Crashes.TrackError(e); #endif await Shutdown().ConfigureAwait(false); } }
private static void Main() { JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = new List <JsonConverter> { new IPEndPointConverter() } }; Config <Config> .Initialize("game.hjson", "NETSPHEREPIRATES_GAMECONF"); var jsonlog = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "game.json"); var logfile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "game.log"); Log.Logger = new LoggerConfiguration() .Destructure.ByTransforming <IPEndPoint>(endPoint => endPoint.ToString()) .Destructure.ByTransforming <EndPoint>(endPoint => endPoint.ToString()) .WriteTo.File(new JsonFormatter(), jsonlog) .WriteTo.File(logfile) .WriteTo.Console(outputTemplate: "[{Level} {SourceContext}] {Message}{NewLine}{Exception}") .MinimumLevel.Debug() .CreateLogger(); AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; TaskScheduler.UnobservedTaskException += OnUnobservedTaskException; Log.Information("Initializing..."); try { AuthDatabase.Initialize(Config.Instance.Database.Auth); GameDatabase.Initialize(Config.Instance.Database.Game); } catch (DatabaseNotFoundException ex) { Log.Error("Database {Name} not found", ex.Name); Environment.Exit(1); } catch (DatabaseVersionMismatchException ex) { Log.Error("Invalid version. Database={CurrentVersion} Required={RequiredVersion}. Run the DatabaseMigrator to update your database.", ex.CurrentVersion, ex.RequiredVersion); Environment.Exit(1); } ItemIdGenerator.Initialize(); CharacterIdGenerator.Initialize(); LicenseIdGenerator.Initialize(); DenyIdGenerator.Initialize(); Club.Initialize(); var listenerThreads = new MultithreadEventLoopGroup(Config.Instance.ListenerThreads); var workerThreads = new MultithreadEventLoopGroup(Config.Instance.WorkerThreads); var workerThread = new SingleThreadEventLoop(); ChatServer.Initialize(new ProudNet.Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = workerThreads, WorkerThread = workerThread }); RelayServer.Initialize(new ProudNet.Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = workerThreads, WorkerThread = workerThread }); GameServer.Initialize(new ProudNet.Configuration { SocketListenerThreads = listenerThreads, SocketWorkerThreads = workerThreads, WorkerThread = workerThread }); FillShop(); Log.Information("Starting server..."); ChatServer.Instance.Listen(Config.Instance.ChatListener); RelayServer.Instance.Listen(Config.Instance.RelayListener, IPAddress.Parse(Config.Instance.IP), Config.Instance.RelayUdpPorts); GameServer.Instance.Listen(Config.Instance.Listener); Log.Information("Ready for connections!"); if (Config.Instance.NoobMode) { Log.Warning("!!! NOOB MODE IS ENABLED! EVERY LOGIN SUCCEEDS AND OVERRIDES ACCOUNT LOGIN DETAILS !!!"); } Console.CancelKeyPress += OnCancelKeyPress; while (true) { var input = Console.ReadLine(); if (input == null) { break; } if (input.Equals("exit", StringComparison.InvariantCultureIgnoreCase) || input.Equals("quit", StringComparison.InvariantCultureIgnoreCase) || input.Equals("stop", StringComparison.InvariantCultureIgnoreCase)) { break; } var args = input.GetArgs(); if (args.Length == 0) { continue; } if (!GameServer.Instance.CommandManager.Execute(null, args)) { Console.WriteLine("Unknown command"); } } Exit(); }
public async Task TestDeadlockOnRemove() { IEventLoop thread1 = new SingleThreadEventLoop(); Bootstrap bootstrap1 = new Bootstrap() .Channel <LocalChannel>().Group(thread1).LocalAddress(new LocalAddress("#1")); IEventLoop thread2 = new SingleThreadEventLoop(); Bootstrap bootstrap2 = new Bootstrap() .Channel <LocalChannel>().Group(thread2).LocalAddress(new LocalAddress("#2")); // pool1 runs on thread2, pool2 runs on thread1 FixedChannelPool pool1 = new FixedChannelPool(bootstrap2, NoopHandler.Instance, 1); FixedChannelPool pool2 = new FixedChannelPool(bootstrap1, NoopHandler.Instance, 1); var channelPoolMap = new TestChannelPoolMap1(pool1, pool2); Assert.Same(pool1, channelPoolMap.Get("#1")); Assert.Same(pool2, channelPoolMap.Get("#2")); // thread1 tries to remove pool1 which is running on thread2 // thread2 tries to remove pool2 which is running on thread1 var barrier = new Barrier(2); var future1 = thread1.SubmitAsync(() => { if (!barrier.SignalAndWait(TimeSpan.FromSeconds(1))) { throw new TimeoutException(); } channelPoolMap.Remove("#1"); return(1); }); var future2 = thread2.SubmitAsync(() => { if (!barrier.SignalAndWait(TimeSpan.FromSeconds(1))) { throw new TimeoutException(); } channelPoolMap.Remove("#2"); return(2); }); // A blocking close on remove will cause a deadlock here and the test will time out try { var result = await TaskUtil.WaitAsync(future1, TimeSpan.FromSeconds(1)); if (!result || !future1.IsSuccess()) { throw new TimeoutException(); } result = await TaskUtil.WaitAsync(future2, TimeSpan.FromSeconds(1)); if (!result || !future2.IsSuccess()) { throw new TimeoutException(); } } catch (TimeoutException) { Assert.False(true); // Fail the test on timeout to distinguish from other errors } finally { pool1.Close(); pool2.Close(); channelPoolMap.Close(); Shutdown(thread1, thread2); } }
public async Task TestDeadlockOnAcquire() { IEventLoop threadA1 = new SingleThreadEventLoop(); Bootstrap bootstrapA1 = new Bootstrap() .Channel <LocalChannel>().Group(threadA1).LocalAddress(new LocalAddress("A1")); IEventLoop threadA2 = new SingleThreadEventLoop(); Bootstrap bootstrapA2 = new Bootstrap() .Channel <LocalChannel>().Group(threadA2).LocalAddress(new LocalAddress("A2")); IEventLoop threadB1 = new SingleThreadEventLoop(); Bootstrap bootstrapB1 = new Bootstrap() .Channel <LocalChannel>().Group(threadB1).LocalAddress(new LocalAddress("B1")); IEventLoop threadB2 = new SingleThreadEventLoop(); Bootstrap bootstrapB2 = new Bootstrap() .Channel <LocalChannel>().Group(threadB2).LocalAddress(new LocalAddress("B2")); FixedChannelPool poolA1 = new FixedChannelPool(bootstrapA1, NoopHandler.Instance, 1); FixedChannelPool poolA2 = new FixedChannelPool(bootstrapB2, NoopHandler.Instance, 1); FixedChannelPool poolB1 = new FixedChannelPool(bootstrapB1, NoopHandler.Instance, 1); FixedChannelPool poolB2 = new FixedChannelPool(bootstrapA2, NoopHandler.Instance, 1); // Synchronize threads on these barriers to ensure order of execution, first wait until each thread is inside // the newPool callbak, then hold the two threads that should lose the match until the first two returns, then // release them to test if they deadlock when trying to release their pools on each other's threads. Barrier arrivalBarrier = new Barrier(4); Barrier releaseBarrier = new Barrier(3); var channelPoolMap = new TestChannelPoolMap0( threadA1, threadA2, threadB1, threadB2, poolA1, poolA2, poolB1, poolB2, arrivalBarrier, releaseBarrier); // Thread A1 calls ChannelPoolMap.get(A) // Thread A2 calls ChannelPoolMap.get(A) // Thread B1 calls ChannelPoolMap.get(B) // Thread B2 calls ChannelPoolMap.get(B) var futureA1 = threadA1.SubmitAsync(() => { return(channelPoolMap.Get("A")); }); var futureA2 = threadA2.SubmitAsync(() => { return(channelPoolMap.Get("A")); }); var futureB1 = threadB1.SubmitAsync(() => { return(channelPoolMap.Get("B")); }); var futureB2 = threadB2.SubmitAsync(() => { return(channelPoolMap.Get("B")); }); // Thread A1 succeeds on updating the map and moves on // Thread B1 succeeds on updating the map and moves on // These should always succeed and return with new pools try { var result = await TaskUtil.WaitAsync(futureA1, TimeSpan.FromSeconds(1)); if (!result || !futureA1.IsSuccess()) { throw new TimeoutException(); } Assert.Same(poolA1, futureA1.Result); result = await TaskUtil.WaitAsync(futureB1, TimeSpan.FromSeconds(1)); if (!result || !futureB1.IsSuccess()) { throw new TimeoutException(); } Assert.Same(poolB1, futureB1.Result); } catch (Exception e) { Shutdown(threadA1, threadA2, threadB1, threadB2); throw e; } // Now release the other two threads which at this point lost the race and will try to clean up the acquired // pools. The expected scenario is that both pools close, in case of a deadlock they will hang. if (!releaseBarrier.SignalAndWait(TimeSpan.FromSeconds(1))) { Assert.False(true); } // Thread A2 fails to update the map and submits close to thread B2 // Thread B2 fails to update the map and submits close to thread A2 // If the close is blocking, then these calls will time out as the threads are waiting for each other // If the close is not blocking, then the previously created pools will be returned try { var result = await TaskUtil.WaitAsync(futureA2, TimeSpan.FromSeconds(1)); if (!result || !futureA2.IsSuccess()) { throw new TimeoutException(); } Assert.Same(poolA1, futureA2.Result); result = await TaskUtil.WaitAsync(futureB2, TimeSpan.FromSeconds(1)); if (!result || !futureB2.IsSuccess()) { throw new TimeoutException(); } Assert.Same(poolB1, futureB2.Result); } catch (TimeoutException) { Assert.False(true); // Fail the test on timeout to distinguish from other errors throw; } finally { poolA1.Close(); poolA2.Close(); poolB1.Close(); poolB2.Close(); channelPoolMap.Close(); Shutdown(threadA1, threadA2, threadB1, threadB2); } }