Example #1
0
        private static void TaskVoiceServerHeartbeat(
            Logger logger,
            CancellationToken cancelToken,
            ClientConnectionData connection,
            BlockingCollection <IMsgPackTypeName> transmitQueue)
        {
            logger.Debug(nameof(TaskVoiceServerHeartbeat) + " started");

            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();
            var keepAlive = new HeartbeatDto()
            {
                Callsign = connection.Callsign
            };

            while (!cancelToken.IsCancellationRequested)
            {
                if (stopWatch.ElapsedMilliseconds > 3000)
                {
                    transmitQueue.Add(keepAlive);
                    stopWatch.Restart();
                }
                Thread.Sleep(500);
            }

            logger.Debug(nameof(TaskVoiceServerHeartbeat) + " stopped");
        }
Example #2
0
 public ClientConnection(string apiServer)
 {
     connection = new ClientConnectionData();
     connection.ApiServerConnection = new ApiServerConnection(apiServer);
     connection.ReceiveAudio        = true;
     connection.Callsign            = null;
     //client = new RestClient(apiServer);
     VoiceServerTransmitQueue = new BlockingCollection <IMsgPackTypeName>();
     VoiceServerReceiveQueue  = new BlockingCollection <IMsgPackTypeName>();
     //DataServerTransmitQueue = new BlockingCollection<IMsgPack>();
     //DataServerReceiveQueue = new BlockingCollection<IMsgPack>();
     logger.Debug(nameof(ClientConnection) + " instantiated");
 }
Example #3
0
        private static void TaskServerConnectionCheck(
            Logger logger,
            CancellationToken cancelToken,
            ClientConnectionData connection,
            Action <DisconnectReasons> disconnectReason)
        {
            logger.Debug(nameof(TaskServerConnectionCheck) + " started");

            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();
            while (!cancelToken.IsCancellationRequested)
            {
                if (stopWatch.ElapsedMilliseconds > 3000)
                {
                    if (connection.IsConnected && !connection.VoiceServerAlive)
                    {
                        logger.Error("Lost connection to Voice Server");
                        disconnectReason(DisconnectReasons.LostConnection);
                    }
                    if (connection.IsConnected && connection.TaskVoiceServerHeartbeat?.Status != TaskStatus.Running)
                    {
                        logger.Error("TaskVoiceServerHeartbeat not running");
                        disconnectReason(DisconnectReasons.InternalLibraryError10);
                    }
                    if (connection.IsConnected && connection.TaskVoiceServerReceive?.Status != TaskStatus.Running)
                    {
                        logger.Error("TaskVoiceServerReceive not running");
                        disconnectReason(DisconnectReasons.InternalLibraryError20);
                    }
                    if (connection.IsConnected && connection.TaskVoiceServerTransmit?.Status != TaskStatus.Running)
                    {
                        logger.Error("TaskVoiceServerTransmit not running");
                        disconnectReason(DisconnectReasons.InternalLibraryError30);
                    }
                    stopWatch.Restart();
                }
                Thread.Sleep(500);
            }

            logger.Debug(nameof(TaskServerConnectionCheck) + " stopped");
        }
Example #4
0
        private static void TaskVoiceServerReceive(
            Logger logger,
            CancellationToken cancelToken,
            ClientConnectionData connection,
            UdpClient udpClient,
            BlockingCollection <IMsgPackTypeName> receiveQueue)
        {
            logger.Debug(nameof(TaskVoiceServerReceive) + " started");

            try
            {
                IPEndPoint sender = new IPEndPoint(IPAddress.Any, 60005);
                byte[]     data;

                while (!cancelToken.IsCancellationRequested)
                {
                    data = udpClient.Receive(ref sender);               //UDP is a datagram protocol, not a streaming protocol, so it's whole datagrams here.
                    if (data.Length < 30 || data.Length > 1500)
                    {
                        continue;
                    }
                    //Could check that the sender has the right IP - but NAT-ing significantly reduces the attack surface here
                    connection.VoiceServerBytesReceived += data.Length;
                    var deserializer = CryptoDtoDeserializer.DeserializeIgnoreSequence(connection.VoiceCryptoChannel, data);
                    if (!deserializer.IsSequenceValid())
                    {
                        logger.Debug("Duplicate or old packet received");
                        continue;       //If a duplicate packet received (because it's UDP) - ignore it
                    }
                    //Crypto DTO stream is only concerned with duplicated or old packets, it doesn't discard out-of-order. Need to find out if Opus discards OOO packets.

                    var dtoName = deserializer.GetDtoName();

                    if (dtoName == "AR")
                    {
                        dtoName = RadioRxDto.TypeNameConst;     //The server will be sending RadioRxDto as "AR" to maintain backwards compatibility for a year or two until old clients get updated.
                    }
                    switch (dtoName)
                    {
                    case RadioRxDto.TypeNameConst:
                    {
                        var dto = deserializer.GetDto <RadioRxDto>();
                        if (connection.ReceiveAudio && connection.IsConnected)
                        {
                            receiveQueue.Add(dto);
                        }
                        break;
                    }

                    case nameof(CallRequestDto):
                    case ShortDtoNames.CallRequest:
                    {
                        var dto = deserializer.GetDto <CallRequestDto>();
                        if (connection.ReceiveAudio && connection.IsConnected)
                        {
                            receiveQueue.Add(dto);
                        }
                        break;
                    }

                    case nameof(CallResponseDto):
                    case ShortDtoNames.CallResponse:
                    {
                        var dto = deserializer.GetDto <CallResponseDto>();
                        if (connection.ReceiveAudio && connection.IsConnected)
                        {
                            receiveQueue.Add(dto);
                        }
                        break;
                    }

                    case nameof(HeartbeatAckDto):
                    case ShortDtoNames.HeartbeatAckDto:
                        connection.LastVoiceServerHeartbeatAckUtc = DateTime.UtcNow;
                        logger.Trace("Received voice server heartbeat");
                        break;
                    }
                }
            }
            catch (SocketException sex)
            {
                if (connection.IsConnected)     //If the socket exception occurs whilst disconnected, it's likely to just be a forced socket closure from doing disconnect().
                {
                    logger.Error(sex);
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }

            logger.Debug(nameof(TaskVoiceServerReceive) + " stopped");
        }
Example #5
0
        private static void TaskVoiceServerTransmit(
            Logger logger,
            CancellationToken cancelToken,
            ClientConnectionData connection,
            UdpClient udpClient,
            IPEndPoint server,
            BlockingCollection <IMsgPackTypeName> transmitQueue)
        {
            logger.Debug(nameof(TaskVoiceServerTransmit) + " started");
            CryptoDtoSerializer serializer = new CryptoDtoSerializer();

            try
            {
                byte[] dataBytes;
                while (!cancelToken.IsCancellationRequested)
                {
                    if (transmitQueue.TryTake(out IMsgPackTypeName obj, 250, cancelToken))
                    {
                        if (connection.IsConnected)
                        {
                            switch (obj.GetType().Name)
                            {
                            case nameof(RadioTxDto):
                                if (logger.IsTraceEnabled)
                                {
                                    logger.Trace(((RadioTxDto)obj).ToDebugString());
                                }
                                dataBytes = serializer.Serialize(connection.VoiceCryptoChannel, CryptoDtoMode.ChaCha20Poly1305, (RadioTxDto)obj);
                                udpClient.Send(dataBytes, dataBytes.Length, server);
                                connection.VoiceServerBytesSent += dataBytes.Length;
                                break;

                            case nameof(CallRequestDto):
                                if (logger.IsTraceEnabled)
                                {
                                    logger.Trace("Sending CallRequestDto");
                                }
                                dataBytes = serializer.Serialize(connection.VoiceCryptoChannel, CryptoDtoMode.ChaCha20Poly1305, (CallRequestDto)obj);
                                udpClient.Send(dataBytes, dataBytes.Length, server);
                                connection.VoiceServerBytesSent += dataBytes.Length;
                                break;

                            case nameof(CallResponseDto):
                                if (logger.IsTraceEnabled)
                                {
                                    logger.Trace("Sending CallResponseDto");
                                }
                                dataBytes = serializer.Serialize(connection.VoiceCryptoChannel, CryptoDtoMode.ChaCha20Poly1305, (CallResponseDto)obj);
                                udpClient.Send(dataBytes, dataBytes.Length, server);
                                connection.VoiceServerBytesSent += dataBytes.Length;
                                break;

                            case nameof(HeartbeatDto):
                                if (logger.IsTraceEnabled)
                                {
                                    logger.Trace("Sending voice server heartbeat");
                                }
                                dataBytes = serializer.Serialize(connection.VoiceCryptoChannel, CryptoDtoMode.ChaCha20Poly1305, (HeartbeatDto)obj);
                                udpClient.Send(dataBytes, dataBytes.Length, server);
                                connection.VoiceServerBytesSent += dataBytes.Length;
                                break;
                            }
                        }
                    }
                }
            }
            catch (OperationCanceledException) { }
            catch (Exception ex)
            {
                logger.Error(ex);
            }

            logger.Debug(nameof(TaskVoiceServerTransmit) + " stopped");
        }