Example #1
0
        /////////////////////////////////////////////////////////////////////
        // CONTROL (LOOP) THREAD
        /////////////////////////////////////////////////////////////////////

        private void ControlThread(object nobjs)
        {
            var networkObjects    = nobjs as object[];
            var tcpListener       = networkObjects[0] as TcpListener;
            var announcer         = networkObjects[1] as UdpClient;
            var clientThreads     = new List <Thread>();
            var flushTimer        = new Marzersoft.Timer();
            var announceTimer     = new Marzersoft.Timer();
            var announceEndpoints = new List <IPEndPoint>();

            while (running)
            {
                Thread.Sleep(1);

                /*
                 * COMP7722: Incoming connection requests are dispatched to their own managing thread.
                 */
                //accept the connection
                while (tcpListener.Pending())
                {
                    //get client
                    TcpClient tcpClient = null;
                    if (CaptureException(() => { tcpClient = tcpListener.AcceptTcpClient(); }))
                    {
                        continue;
                    }

                    //create client thread
                    clientThreads.Add(new Thread(ClientThread));
                    clientThreads.Last().Name         = "OTEX Server ClientThread";
                    clientThreads.Last().IsBackground = false;
                    clientThreads.Last().Start(tcpClient);
                }

                //announce
                if (startParams.Public && announceTimer.Seconds >= 1.0)
                {
                    CaptureException(() =>
                    {
                        //create endpoints if they don't exist
                        if (announceEndpoints.Count == 0)
                        {
                            for (int i = AnnouncePorts.First; i <= AnnouncePorts.Last; ++i)
                            {
                                announceEndpoints.Add(new IPEndPoint(IPAddress.Broadcast, i));
                            }
                        }

                        //serialize a server description of the current state
                        var announceData = (new ServerDescription(this)).Serialize();

                        //broadcast to the port range
                        foreach (IPEndPoint ep in announceEndpoints)
                        {
                            announcer.Send(announceData, announceData.Length, ep);
                        }
                    });
                    announceTimer.Reset();
                }

                /*
                 * COMP7722: File contents is synchronized to disk periodically (every 15 seconds)
                 */
                //flush file contents to disk periodically
                if (startParams.FilePath.Length > 0 && flushTimer.Seconds >= 15.0)
                {
                    lock (stateLock)
                    {
                        CaptureException(() => { SyncFileContents(); });
                    }
                    flushTimer.Reset();
                }
            }

            //stop listeners and announcer
            CaptureException(() => { tcpListener.Stop(); });
            if (announcer != null)
            {
                CaptureException(() => { announcer.Close(); });
            }

            //wait for client threads to close
            foreach (Thread thread in clientThreads)
            {
                thread.Join();
            }

            //final flush to disk (don't need a lock this time, all client threads have stopped)
            if (startParams.FilePath.Length > 0)
            {
                CaptureException(() => { SyncFileContents(); });
            }
        }
Example #2
0
        /////////////////////////////////////////////////////////////////////
        // CONTROL (LOOP) THREAD
        /////////////////////////////////////////////////////////////////////

        private void ControlThread(object o)
        {
            var objs   = o as object[];
            var client = objs[0] as TcpClient;
            var stream = objs[1] as PacketStream;
            var lastOpsRequestTimer = new Marzersoft.Timer();

            while (!clientSideDisconnection && stream.Connected)
            {
                Thread.Sleep(1);

                //listen for packets first
                //(returns true if the server has asked us to disconnect)
                if (Listen(stream))
                {
                    //override clientSideDisconnection so we don't send
                    //unnecessarily send a disconnection to the server
                    clientSideDisconnection = false;
                    break;
                }

                //send periodic requests for new operations
                if (!awaitingOperationList && lastOpsRequestTimer.Seconds >= updateInterval)
                {
                    lock (operationsLock)
                    {
                        /*
                         * COMP7722: step 1 & 2 of HOB: all outgoing operations sent to the server,
                         * clearing the local outgoing operation buffer.
                         */

                        //perform SLOT(OB,CIB) (1)
                        if (outgoingOperations.Count > 0 && incomingOperations.Count > 0)
                        {
                            Operation.SymmetricLinearTransform(outgoingOperations, incomingOperations);
                        }

                        //send request (2)
                        if (CaptureException(() => { stream.Write(ID,
                                                                  new OperationList(outgoingOperations.Count > 0 ? outgoingOperations : null)); }))
                        {
                            break;
                        }
                        awaitingOperationList = true;

                        //clear outgoing packet list (1)
                        if (outgoingOperations.Count > 0)
                        {
                            outgoingOperations.Clear();
                        }

                        //apply any incoming operations (also clears list)
                        InvokeRemoteOperations(incomingOperations);
                    }
                    lastOpsRequestTimer.Reset();
                }

                //send off any pending metadata updates
                if (pendingMetadata != null)
                {
                    lock (pendingMetadataLock)
                    {
                        if (pendingMetadata != null)
                        {
                            if (CaptureException(() => { stream.Write(ID, new ClientMetadata(ID, pendingMetadata)); }))
                            {
                                break;
                            }
                            pendingMetadata = null;
                        }
                    }
                }
            }

            //disconnect
            connected = false;
            if (clientSideDisconnection) //tell the server the user is disconnecting client-side
            {
                CaptureException(() => { stream.Write(ID, new DisconnectionRequest()); });
            }
            stream.Dispose();
            client.Close();
            outgoingOperations.Clear();
            incomingOperations.Clear();
            pendingMetadata = null;

            //fire event
            OnDisconnected?.Invoke(this, !clientSideDisconnection);
            clientSideDisconnection = false;
        }
Example #3
0
        /////////////////////////////////////////////////////////////////////
        // CONTROL (LOOP) THREAD
        /////////////////////////////////////////////////////////////////////

        private void ControlThread(object uc)
        {
            var udpClient  = uc as UdpClient;
            var checkTimer = new Marzersoft.Timer();

            while (!isDisposed)
            {
                Thread.Sleep(250);

                //read all waiting packets
                while (udpClient.Available > 0)
                {
                    //read packet
                    IPEndPoint senderAnnounceEndpoint = null;
                    byte[]     packetData             = null;
                    if (CaptureException(() => { packetData = udpClient.Receive(ref senderAnnounceEndpoint); }))
                    {
                        continue;
                    }

                    //deserialize packet
                    ServerDescription packet         = null;
                    IPEndPoint        senderEndPoint = null;
                    if (CaptureException(() =>
                    {
                        packet = packetData.Deserialize <ServerDescription>();
                        senderEndPoint = new IPEndPoint(senderAnnounceEndpoint.Address, packet.Port);
                    }))
                    {
                        continue;
                    }

                    //process
                    lock (activeServers)
                    {
                        ServerDescription knownServer = null;
                        if (!activeServers.TryGetValue(senderEndPoint, out knownServer))
                        {
                            activeServers[senderEndPoint] = knownServer = new ServerDescription(senderEndPoint, packet);
                            OnServerAdded?.Invoke(this, knownServer);
                        }
                        else
                        {
                            CaptureException(() => { knownServer.Update(senderEndPoint, packet); });
                        }
                    }
                }

                //periodically check server inactive state and update pings
                if (checkTimer.Seconds >= 1.0)
                {
                    lock (activeServers)
                    {
                        //cull inactive servers
                        var inactiveServers = activeServers
                                              .Where((kvp) => { return(kvp.Value.LastUpdated >= 10.0); })
                                              .ToList();
                        foreach (var inactive in inactiveServers)
                        {
                            activeServers.Remove(inactive.Key);
                            inactive.Value.Active = false; //invokes event
                        }

                        //update pings
                        if (autoPing)
                        {
                            foreach (var active in activeServers)
                            {
                                if (active.Value.LastPinged >= 10.0)
                                {
                                    active.Value.UpdatePing();
                                }
                            }
                        }
                    }
                    checkTimer.Reset();
                }
            }

            //close listener
            CaptureException(() => { udpClient.Close(); });
        }