/// <summary>
        /// Thread that is responsible for connection to LOC and processing LOC updates.
        /// If the LOC is not reachable, the thread will wait until it is reachable.
        /// If connection to LOC is established and closed for any reason, the thread will try to reconnect.
        /// </summary>
        private async void LocConnectionThread()
        {
            LogDiagnosticContext.Start();

            log.Info("()");

            locConnectionThreadFinished.Reset();

            try
            {
                while (!ShutdownSignaling.IsShutdown)
                {
                    // Connect to LOC server.
                    if (await client.ConnectAsync())
                    {
                        // Announce our primary server interface to LOC.
                        if (await client.RegisterPrimaryServerRoleAsync(Config.Configuration.ServerRoles.GetRolePort((uint)ServerRole.Primary), Iop.Locnet.ServiceType.Profile))
                        {
                            // Ask LOC server about initial set of neighborhood nodes.
                            if (await GetNeighborhoodInformationAsync())
                            {
                                // Receive and process updates.
                                await client.ReceiveMessageLoopAsync();
                            }

                            await client.DeregisterPrimaryServerRoleAsync();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                if (!ShutdownSignaling.IsShutdown)
                {
                    log.Error("Exception occurred (and rethrowing): {0}", e.ToString());
                    await Task.Delay(5000);

                    throw e;
                }
                else
                {
                    log.Debug("Shutdown invoked exception.");
                }
            }

            if (client != null)
            {
                client.Dispose();
            }
            locConnectionThreadFinished.Set();

            log.Info("(-)");

            LogDiagnosticContext.Stop();
        }
Exemplo n.º 2
0
        /// <summary>
        /// Thread that is responsible for late initialization of network servers.
        /// This is needed because in order for the proximity server to run, it must know its location.
        /// The location is received from LOC server, but there is no guarantee LOC server is running
        /// when the proximity server starts.
        /// </summary>
        private async void DelayedStartupThread()
        {
            LogDiagnosticContext.Start();

            log.Info("()");

            delayedStartupThreadFinished.Reset();

            try
            {
                Console.WriteLine("Waiting for location initialization ...");
                LocationBasedNetwork loc = (LocationBasedNetwork)Base.ComponentDictionary[LocationBasedNetwork.ComponentName];
                bool locInit             = false;
                try
                {
                    locInit = await loc.LocLocationInitializedEvent.Task;
                }
                catch
                {
                    // Catch cancellation exception.
                    log.Trace("Shutdown detected.");
                }

                if (locInit)
                {
                    log.Debug("LOC location is initialized, we can continue with Network server component initialization.");
                    if (base.Init())
                    {
                        RegisterCronJobs();
                        DelayedStartupCompletedEvent.TrySetResult(true);
                    }
                    else
                    {
                        log.Error("Delayed initialization failed, initiating shutdown.");
                        Base.ComponentManager.GlobalShutdown.SignalShutdown();
                    }
                    Console.WriteLine("Location initialization completed.");
                }
            }
            catch (Exception e)
            {
                log.Error("Exception occurred (and rethrowing): {0}", e.ToString());
                await Task.Delay(5000);

                throw e;
            }

            delayedStartupThreadFinished.Set();

            log.Info("(-)");

            LogDiagnosticContext.Stop();
        }
Exemplo n.º 3
0
        /// <summary>
        /// Thread procedure that is responsible for accepting new clients on the TCP server port.
        /// New clients are put into clientQueue, from which they are consumed by clientQueueHandlerThread.
        /// </summary>
        private void AcceptThread()
        {
            LogDiagnosticContext.Start();

            log.Trace("()");

            acceptThreadFinished.Reset();

            AutoResetEvent acceptTaskEvent = new AutoResetEvent(false);

            while (!ShutdownSignaling.IsShutdown)
            {
                log.Debug("Waiting for new client.");
                Task <TcpClient> acceptTask = Listener.AcceptTcpClientAsync();
                acceptTask.ContinueWith(t => acceptTaskEvent.Set());

                WaitHandle[] handles = new WaitHandle[] { acceptTaskEvent, ShutdownSignaling.ShutdownEvent };
                int          index   = WaitHandle.WaitAny(handles);
                if (handles[index] == ShutdownSignaling.ShutdownEvent)
                {
                    log.Info("Shutdown detected.");
                    break;
                }

                try
                {
                    // acceptTask is finished here, asking for Result won't block.
                    TcpClient client = acceptTask.Result;
                    EndPoint  ep     = client.Client.RemoteEndPoint;
                    lock (clientQueueLock)
                    {
                        clientQueue.Enqueue(client);
                    }
                    log.Debug("New client '{0}' accepted.", ep);
                    clientQueueEvent.Set();
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred: {0}", e.ToString());
                }
            }

            acceptThreadFinished.Set();

            log.Trace("(-)");

            LogDiagnosticContext.Stop();
        }
Exemplo n.º 4
0
        /// <summary>
        /// Handler for each client that connects to the TCP server.
        /// </summary>
        /// <param name="Client">Client that is connected to TCP server.</param>
        /// <remarks>The client is being handled in the processing loop until the connection to it is terminated by either side.</remarks>
        private async void ClientHandlerAsync(IncomingClientBase Client)
        {
            LogDiagnosticContext.Start();

            log.Info("(Client.RemoteEndPoint:{0})", Client.RemoteEndPoint);

            clientList.AddNetworkPeer(Client);
            log.Debug("Client ID set to {0}.", Client.Id.ToHex());

            await Client.ReceiveMessageLoop();

            // Free resources used by the client.
            clientList.RemoveNetworkPeer(Client);
            await Client.HandleDisconnect();

            Client.Dispose();

            log.Info("(-)");

            LogDiagnosticContext.Stop();
        }
Exemplo n.º 5
0
        /// <summary>
        /// Handler for each client that connects to the TCP server.
        /// </summary>
        /// <param name="Client">Client that is connected to TCP server.</param>
        private async void ClientHandlerAsync(TcpClient Client)
        {
            LogDiagnosticContext.Start();

            log.Debug("(Client.Client.RemoteEndPoint:{0})", Client.Client.RemoteEndPoint);

            connectedProfileServer = Client;
            connectedProfileServerMessageBuilder = new LocMessageBuilder(0, new List <SemVer>()
            {
                SemVer.V100
            });

            await ReceiveMessageLoop(Client, connectedProfileServerMessageBuilder);

            connectedProfileServerWantsUpdates = false;
            connectedProfileServer             = null;
            Client.Dispose();

            log.Debug("(-)");

            LogDiagnosticContext.Stop();
        }
Exemplo n.º 6
0
        /// <summary>
        /// Callback routine that is called once the timeoutTimer expires.
        /// <para>
        /// If relay status is WaitingForCalleeResponse, the callee has to reply to the incoming call notification
        /// within a reasonable time. If it does the timer is cancelled. If it does not, the timeout occurs.
        /// </para>
        /// <para>
        /// If relay status is WaitingForFirstInitMessage, both clients are expected to connect to clAppService port
        /// and send an initial message over that service. The timeoutTimer expires when none of the clients
        /// connects to clAppService port and sends its initialization message within a reasonable time.
        /// </para>
        /// <para>
        /// Then if relay status is WaitingForSecondInitMessage, the profile server receives a message from the first client
        /// on clAppService port, it starts the timer again, which now expires if the second client does not connect
        /// and send its initial message within a reasonable time.
        /// </para>
        /// </summary>
        /// <param name="state">Status of the relay when the timer was installed.</param>
        private async void TimeoutCallback(object State)
        {
            LogDiagnosticContext.Start();

            RelayConnectionStatus previousStatus = (RelayConnectionStatus)State;

            log.Trace("(State:{0})", previousStatus);

            IncomingClient    clientToSendMessage = null;
            PsProtocolMessage messageToSend       = null;
            bool destroyRelay = false;

            await lockObject.WaitAsync();

            if (timeoutTimer != null)
            {
                switch (status)
                {
                case RelayConnectionStatus.WaitingForCalleeResponse:
                {
                    // The caller requested the call and the callee was notified.
                    // The callee failed to send us response on time, this is situation 2)
                    // from ProcessMessageCallIdentityApplicationServiceRequestAsync.
                    // We send ERROR_NOT_AVAILABLE to the caller and destroy the relay.
                    log.Debug("Callee failed to reply to the incoming call notification, closing relay.");

                    clientToSendMessage = caller;
                    messageToSend       = caller.MessageBuilder.CreateErrorNotAvailableResponse(pendingMessage);
                    break;
                }

                case RelayConnectionStatus.WaitingForFirstInitMessage:
                {
                    // Neither client joined the channel on time, nothing to do, just destroy the relay.
                    log.Debug("None of the clients joined the relay on time, closing relay.");
                    break;
                }

                case RelayConnectionStatus.WaitingForSecondInitMessage:
                {
                    // One client is waiting for the other one to join, but the other client failed to join on time.
                    // We send ERROR_NOT_FOUND to the waiting client and close its connection.
                    log.Debug("{0} failed to join the relay on time, closing relay.", callee != null ? "Caller" : "Callee");

                    clientToSendMessage = callee != null ? callee : caller;
                    messageToSend       = clientToSendMessage.MessageBuilder.CreateErrorNotFoundResponse(pendingMessage);
                    break;
                }

                default:
                    log.Debug("Time out triggered while the relay status was {0}.", status);
                    break;
                }

                // In case of any timeouts, we just destroy the relay.
                destroyRelay = true;
            }
            else
            {
                log.Debug("Timeout timer of relay '{0}' has been destroyed, no action taken.", id);
            }

            lockObject.Release();


            if (messageToSend != null)
            {
                if (!await clientToSendMessage.SendMessageAsync(messageToSend))
                {
                    log.Warn("Unable to send message to the client ID {0} in relay '{1}', maybe it is not connected anymore.", clientToSendMessage.Id.ToHex(), id);
                }
            }

            if (destroyRelay)
            {
                Server serverComponent = (Server)Base.ComponentDictionary[Server.ComponentName];
                await serverComponent.RelayList.DestroyNetworkRelay(this);
            }

            log.Trace("(-)");

            LogDiagnosticContext.Stop();
        }