예제 #1
0
        public static IConfiguration ConfigureNLog(this IConfiguration configuration, ILogger logger = null)
        {
            try
            {
                logger?.LogInformation("Configuration has been reloaded - applying LoggingConfiguration");

                var nLogSection = configuration.GetSection("LoggingConfiguration")?.GetSection("NLog");

                if (nLogSection is null)
                {
                    logger?.LogInformation("Section JsonLoggingConfiguration:NLog not found; skipping reconfiguration");
                    return(configuration);
                }

                LogManager.Configuration = new NLogLoggingConfiguration(nLogSection);

                logger?.LogInformation("new LoggingConfiguration has been applied");
            }
            catch (Exception e)
            {
                logger?.LogWarning($"new LoggingConfiguration could not be applied: {e}");
            }

            return(configuration);
        }
예제 #2
0
        static async Task Main()
        {
            Console.WriteLine("SIPSorcery Getting Started Video Call Demo");
            Console.WriteLine("Press ctrl-c to exit.");

            Log = AddConsoleLogger();
            ManualResetEvent exitMRE = new ManualResetEvent(false);

            _sipTransport = new SIPTransport();

            EnableTraceLogs(_sipTransport);

            // Open a window to display the video feed from the remote SIP party.
            _form          = new Form();
            _form.AutoSize = true;
            _form.BackgroundImageLayout = ImageLayout.Center;
            _localVideoPicBox           = new PictureBox
            {
                Size     = new Size(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT),
                Location = new Point(0, 0),
                Visible  = true
            };
            _remoteVideoPicBox = new PictureBox
            {
                Size     = new Size(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT),
                Location = new Point(0, VIDEO_FRAME_HEIGHT),
                Visible  = true
            };
            _form.Controls.Add(_localVideoPicBox);
            _form.Controls.Add(_remoteVideoPicBox);

            Application.EnableVisualStyles();
            ThreadPool.QueueUserWorkItem(delegate { Application.Run(_form); });

            ManualResetEvent formMre = new ManualResetEvent(false);

            _form.Activated += (object sender, EventArgs e) => formMre.Set();

            Console.WriteLine("Waiting for form activation.");
            formMre.WaitOne();

            _sipTransport.SIPTransportRequestReceived += OnSIPTransportRequestReceived;

            string executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            var userAgent = new SIPUserAgent(_sipTransport, null, true);

            userAgent.OnCallHungup += (dialog) => exitMRE.Set();
            var windowsAudioEndPoint = new WindowsAudioEndPoint(new AudioEncoder());

            windowsAudioEndPoint.RestrictFormats(format => format.Codec == AudioCodecsEnum.PCMU);
            var windowsVideoEndPoint = new WindowsVideoEndPoint(new VpxVideoEncoder());

            // Fallback to a test pattern source if accessing the Windows webcam fails.
            var testPattern = new VideoTestPatternSource(new VpxVideoEncoder());

            MediaEndPoints mediaEndPoints = new MediaEndPoints
            {
                AudioSink   = windowsAudioEndPoint,
                AudioSource = windowsAudioEndPoint,
                VideoSink   = windowsVideoEndPoint,
                VideoSource = windowsVideoEndPoint,
            };

            var voipMediaSession = new VoIPMediaSession(mediaEndPoints, testPattern);

            voipMediaSession.AcceptRtpFromAny = true;

            windowsVideoEndPoint.OnVideoSourceRawSample += (uint durationMilliseconds, int width, int height, byte[] sample, VideoPixelFormatsEnum pixelFormat) =>
            {
                _form?.BeginInvoke(new Action(() =>
                {
                    unsafe
                    {
                        fixed(byte *s = sample)
                        {
                            System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap(width, height, width * 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)s);
                            _localVideoPicBox.Image        = bmpImage;
                        }
                    }
                }));
            };

            Console.WriteLine("Starting local video source...");
            await windowsVideoEndPoint.StartVideo().ConfigureAwait(false);

            // Place the call and wait for the result.
            Task <bool> callTask = userAgent.Call(DESTINATION, null, null, voipMediaSession);

            callTask.Wait(CALL_TIMEOUT_SECONDS * 1000);

            if (callTask.Result)
            {
                Log.LogInformation("Call attempt successful.");
                windowsVideoEndPoint.OnVideoSinkDecodedSample += (byte[] bmp, uint width, uint height, int stride, VideoPixelFormatsEnum pixelFormat) =>
                {
                    _form?.BeginInvoke(new Action(() =>
                    {
                        unsafe
                        {
                            fixed(byte *s = bmp)
                            {
                                System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap((int)width, (int)height, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)s);
                                _remoteVideoPicBox.Image       = bmpImage;
                            }
                        }
                    }));
                };

                windowsAudioEndPoint.PauseAudio().Wait();
                voipMediaSession.AudioExtrasSource.SetSource(AudioSourcesEnum.Music);
            }
            else
            {
                Log.LogWarning("Call attempt failed.");
                Console.WriteLine("Press ctrl-c to exit.");
            }

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                Log.LogInformation("Exiting...");
                exitMRE.Set();
            };
            exitMRE.WaitOne();

            if (userAgent.IsCallActive)
            {
                Log.LogInformation("Hanging up.");
                userAgent.Hangup();

                Task.Delay(1000).Wait();
            }

            // Clean up.
            _form.BeginInvoke(new Action(() => _form.Close()));
            _sipTransport.Shutdown();
        }
예제 #3
0
        static async Task Main(string[] args)
        {
            string videoCodec = FFMPEG_DEFAULT_CODEC;

            if (args?.Length > 0)
            {
                switch (args[0].ToLower())
                {
                case FFMPEG_VP8_CODEC:
                case FFMPEG_VP9_CODEC:
                case FFMPEG_H264_CODEC:
                    videoCodec = args[0].ToLower();
                    break;

                default:
                    Console.WriteLine($"Video codec option not recognised. Valid values are {FFMPEG_VP8_CODEC}, {FFMPEG_VP9_CODEC} and {FFMPEG_H264_CODEC}. Using {videoCodec}.");
                    break;
                }
            }

            CancellationTokenSource exitCts = new CancellationTokenSource();

            logger = AddConsoleLogger();

            string ffmpegCommand = String.Format(FFMPEG_DEFAULT_COMMAND, videoCodec, FFMPEG_DEFAULT_RTP_PORT, FFMPEG_SDP_FILE);

            // Start web socket.
            Console.WriteLine("Starting web socket server...");
            _webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT);
            //_webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT, true);
            //_webSocketServer.SslConfiguration.ServerCertificate = new X509Certificate2(LOCALHOST_CERTIFICATE_PATH);
            //_webSocketServer.SslConfiguration.CheckCertificateRevocation = false;
            //_webSocketServer.Log.Level = WebSocketSharp.LogLevel.Debug;
            _webSocketServer.AddWebSocketService <WebRtcClient>("/", (client) =>
            {
                client.WebSocketOpened   += SendOffer;
                client.OnMessageReceived += WebSocketMessageReceived;
            });

            if (File.Exists(FFMPEG_SDP_FILE))
            {
                var sdp      = SDP.ParseSDPDescription(File.ReadAllText(FFMPEG_SDP_FILE));
                var videoAnn = sdp.Media.Single(x => x.Media == SDPMediaTypesEnum.video);
                if (videoAnn.MediaFormats.Values.First().Name().ToLower() != videoCodec)
                {
                    logger.LogWarning($"Removing existing ffmpeg SDP file {FFMPEG_SDP_FILE} due to codec mismatch.");
                    File.Delete(FFMPEG_SDP_FILE);
                }
            }

            Console.WriteLine("Start ffmpeg using the command below and then initiate a WebRTC connection from the browser");
            Console.WriteLine(ffmpegCommand);

            if (!File.Exists(FFMPEG_SDP_FILE))
            {
                Console.WriteLine();
                Console.WriteLine($"Waiting for {FFMPEG_SDP_FILE} to appear...");
            }

            await Task.Run(() => StartFfmpegListener(FFMPEG_SDP_FILE, exitCts.Token));

            Console.WriteLine($"ffmpeg listener successfully created on port {FFMPEG_DEFAULT_RTP_PORT} with video format {_ffmpegVideoFormat.Name()}.");

            _webSocketServer.Start();

            Console.WriteLine();
            Console.WriteLine($"Waiting for browser web socket connection to {_webSocketServer.Address}:{_webSocketServer.Port}...");

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            await Task.Run(() => OnKeyPress(exitCts.Token));

            _webSocketServer.Stop();
        }
예제 #4
0
 private static void SIPBadRequestInTraceEvent(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, string message, SIPValidationFieldsEnum sipErrorField, string rawMessage)
 {
     logger.LogWarning("Bad SIPRequest. Field=" + sipErrorField + ", Message=" + message + ", Remote=" + remoteEndPoint.ToString() + ".");
 }
예제 #5
0
        /// <summary>
        /// Checks that a bound socket is able to receive. The need for this test arose when it was found
        /// that Windows was allocating the same port if a bind was attempted on 0.0.0.0:0 and then [::]:0.
        /// Only one of the two sockets could then receive packets to the OS allocated port.
        /// This check is an attempt to work around the behaviour, see
        /// https://github.com/dotnet/runtime/issues/36618
        /// </summary>
        /// <param name="socket">The bound socket to check for a receive.</param>
        /// <param name="bindAddress">Optional. If the socket was bound to a single specific address
        /// this parameter needs to be set so the test can send to it. If not set the test will send to
        /// the IPv4 loopback addresses.</param>
        /// <returns>True is the receive was successful and the socket is usable. False if not.</returns>
        private bool DoTestReceive(Socket socket, IPAddress bindAddress)
        {
            try
            {
                if (bindAddress != null)
                {
                    logger.LogDebug($"DoTestReceive for {socket.LocalEndPoint} and bind address {bindAddress}.");
                }
                else
                {
                    logger.LogDebug($"DoTestReceive for {socket.LocalEndPoint}.");
                }

                byte[]           buffer = new byte[MAGIC_COOKIE.Length];
                ManualResetEvent mre    = new ManualResetEvent(false);
                int bytesRead           = 0;

                void endReceive(IAsyncResult ar)
                {
                    try
                    {
                        if (socket != null)
                        {
                            bytesRead = socket.EndReceive(ar);
                        }
                    }
                    catch (Exception) { }
                    mre.Set();
                };

                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, endReceive, null);

                int sendToPort = (socket.LocalEndPoint as IPEndPoint).Port;

                IPAddress sendToAddress = bindAddress ?? IPAddress.Loopback;
                if (IPAddress.IPv6Any.Equals(sendToAddress))
                {
                    sendToAddress = IPAddress.IPv6Loopback;
                }
                else if (IPAddress.Any.Equals(sendToAddress))
                {
                    sendToAddress = IPAddress.Loopback;
                }

                IPEndPoint sendTo = new IPEndPoint(sendToAddress, sendToPort);
                socket.SendTo(MAGIC_COOKIE, sendTo);

                if (mre.WaitOne(TimeSpan.FromMilliseconds(TEST_RECEIVE_TIMEOUT_MILLISECONDS), false))
                {
                    // The receive worked. Check that the magic cookie was received.
                    if (bytesRead != MAGIC_COOKIE.Length)
                    {
                        logger.LogDebug("Bytes read was wrong length for magic cookie in DoTestReceive.");
                        return(false);
                    }
                    else if (Encoding.ASCII.GetString(buffer) != Encoding.ASCII.GetString(MAGIC_COOKIE))
                    {
                        logger.LogDebug("The bytes read did not match the magic cookie in DoTestReceive.");
                        return(false);
                    }
                    else
                    {
                        return(true);
                    }
                }
                else
                {
                    logger.LogDebug("Timed out waiting for magic cookie in DoTestReceive.");
                    return(false);
                }
            }
            catch (Exception excp)
            {
                logger.LogWarning($"DoTestReceive received failed with exception {excp.Message}");
                return(false);
            }
        }
예제 #6
0
        /// <summary>
        /// Process user key presses.
        /// </summary>
        /// <param name="exit">The cancellation token to set if the user requests to quit the application.</param>
        private static async Task OnKeyPress(CancellationToken exit)
        {
            try
            {
                while (!exit.WaitHandle.WaitOne(0))
                {
                    var keyProps = Console.ReadKey();

                    if (keyProps.KeyChar == 'c')
                    {
                        // Place an outgoing call.
                        var ua = new SIPUserAgent(_sipTransport, null);
                        ua.ClientCallTrying   += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
                        ua.ClientCallRinging  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
                        ua.ClientCallFailed   += (uac, err) => Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                        ua.ClientCallAnswered += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                        ua.OnDtmfTone         += (key, duration) => OnDtmfTone(ua, key, duration);
                        ua.OnRtpEvent         += (evt, hdr) => Log.LogDebug($"rtp event {evt.EventID}, duration {evt.Duration}, end of event {evt.EndOfEvent}, timestamp {hdr.Timestamp}, marker {hdr.MarkerBit}.");
                        ua.OnCallHungup       += OnHangup;

                        var rtpSession = CreateRtpSession(ua, null);
                        var callResult = await ua.Call(DEFAULT_CALL_DESTINATION, null, null, rtpSession);

                        if (callResult)
                        {
                            await rtpSession.Start();

                            _calls.TryAdd(ua.Dialogue.CallId, ua);
                        }
                    }
                    else if (keyProps.KeyChar == 'd')
                    {
                        if (_calls.Count == 0)
                        {
                            Log.LogWarning("There are no active calls.");
                        }
                        else
                        {
                            var  newestCall = _calls.OrderByDescending(x => x.Value.Dialogue.Inserted).First();
                            byte randomDtmf = (byte)Crypto.GetRandomInt(0, 15);
                            Log.LogInformation($"Sending DTMF {randomDtmf} to {newestCall.Key}.");
                            await newestCall.Value.SendDtmf(randomDtmf);
                        }
                    }
                    else if (keyProps.KeyChar == 'h')
                    {
                        if (_calls.Count == 0)
                        {
                            Log.LogWarning("There are no active calls.");
                        }
                        else
                        {
                            var oldestCall = _calls.OrderBy(x => x.Value.Dialogue.Inserted).First();
                            Log.LogInformation($"Hanging up call {oldestCall.Key}.");
                            oldestCall.Value.OnCallHungup -= OnHangup;
                            oldestCall.Value.Hangup();
                            _calls.TryRemove(oldestCall.Key, out _);
                        }
                    }
                    else if (keyProps.KeyChar == 'H')
                    {
                        if (_calls.Count == 0)
                        {
                            Log.LogWarning("There are no active calls.");
                        }
                        else
                        {
                            foreach (var call in _calls)
                            {
                                Log.LogInformation($"Hanging up call {call.Key}.");
                                call.Value.Hangup();
                            }
                            _calls.Clear();
                        }
                    }
                    else if (keyProps.KeyChar == 'l')
                    {
                        if (_calls.Count == 0)
                        {
                            Log.LogInformation("There are no active calls.");
                        }
                        else
                        {
                            Log.LogInformation("Current call list:");
                            foreach (var call in _calls)
                            {
                                Log.LogInformation($"{call.Key}: {call.Value.Dialogue.RemoteTarget}");
                            }
                        }
                    }
                    else if (keyProps.KeyChar == 'r')
                    {
                        if (_registrations.Count == 0)
                        {
                            Log.LogInformation("There are no active registrations.");
                        }
                        else
                        {
                            Log.LogInformation("Current registration list:");
                            foreach (var registration in _registrations)
                            {
                                Log.LogInformation($"{registration.Key}: is registered {registration.Value.IsRegistered}, last attempt at {registration.Value.LastRegisterAttemptAt}");
                            }
                        }
                    }
                    else if (keyProps.KeyChar == 't')
                    {
                        if (_calls.Count == 0)
                        {
                            Log.LogWarning("There are no active calls.");
                        }
                        else
                        {
                            var newestCall = _calls.OrderByDescending(x => x.Value.Dialogue.Inserted).First();
                            Log.LogInformation($"Transferring call {newestCall.Key} to {DEFAULT_TRANSFER_DESTINATION}.");
                            bool transferResult = await newestCall.Value.BlindTransfer(SIPURI.ParseSIPURI(DEFAULT_TRANSFER_DESTINATION), TimeSpan.FromSeconds(3), exit);

                            if (transferResult)
                            {
                                Log.LogInformation($"Transferring succeeded.");

                                // The remote party will often put us on hold after the transfer.
                                await Task.Delay(1000);

                                newestCall.Value.OnCallHungup -= OnHangup;
                                newestCall.Value.Hangup();
                                _calls.TryRemove(newestCall.Key, out _);
                            }
                            else
                            {
                                Log.LogWarning($"Transfer attempt failed.");
                            }
                        }
                    }
                    else if (keyProps.KeyChar == 'q')
                    {
                        // Quit application.
                        Log.LogInformation("Quitting");
                        break;
                    }
                }
            }
            catch (Exception excp)
            {
                Log.LogError($"Exception OnKeyPress. {excp.Message}.");
            }
        }
예제 #7
0
        private RTCPeerConnection Createpc()
        {
            List <RTCCertificate> presetCertificates = null;

            if (File.Exists(LOCALHOST_CERTIFICATE_PATH))
            {
                var localhostCert = new X509Certificate2(LOCALHOST_CERTIFICATE_PATH, (string)null, X509KeyStorageFlags.Exportable);
                presetCertificates = new List <RTCCertificate> {
                    new RTCCertificate {
                        Certificate = localhostCert
                    }
                };
            }

            RTCConfiguration pcConfiguration = new RTCConfiguration
            {
                certificates = presetCertificates,
            };

            var pc = new RTCPeerConnection(pcConfiguration);

            pc.GetRtpChannel().MdnsResolve = MdnsResolve;
            //pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isrelay) => logger.LogDebug($"{_peerName}: STUN message received from {ep}, message class {msg.Header.MessageClass}.");

            var dataChannel = pc.createDataChannel(_dataChannelLabel, null);

            dataChannel.onDatamessage -= DataChannel_onDatamessage;
            dataChannel.onDatamessage += DataChannel_onDatamessage;
            _dataChannels.Add(_dataChannelLabel, dataChannel);

            pc.onicecandidateerror        += (candidate, error) => logger.LogWarning($"{_peerName}: Error adding remote ICE candidate. {error} {candidate}");
            pc.oniceconnectionstatechange += (state) => logger.LogDebug($"{_peerName}: ICE connection state change to {state}.");
            pc.onconnectionstatechange    += (state) =>
            {
                logger.LogDebug($"{_peerName}: Peer connection state changed to {state}.");

                if (state == RTCPeerConnectionState.disconnected || state == RTCPeerConnectionState.failed)
                {
                    pc.Close("remote disconnection");
                }
            };

            pc.onicecandidate += (candidate) =>
            {
                if (pc.signalingState == RTCSignalingState.have_local_offer ||
                    pc.signalingState == RTCSignalingState.have_remote_offer)
                {
                    OnIceCandidateAvailable?.Invoke(new RTCIceCandidateInit()
                    {
                        candidate     = candidate.ToString(),
                        sdpMid        = candidate.sdpMid,
                        sdpMLineIndex = candidate.sdpMLineIndex
                    });
                }
            };

            pc.ondatachannel += (dc) =>
            {
                dc.onopen        += () => logger.LogDebug($"{_peerName}: Data channel now open label {dc.label}, stream ID {dc.id}.");
                dc.onDatamessage -= DataChannel_onDatamessage;
                dc.onDatamessage += DataChannel_onDatamessage;
                logger.LogDebug($"{_peerName}: Data channel created by remote peer, label {dc.label}, stream ID {dc.id}.");
                _dataChannels.Add(dc.label, dc);
            };

            return(pc);
        }
예제 #8
0
        public Config LoadArgs(IConfiguration config, ILogger logger)
        {
            var networkType = config.GetNetworkType();

            logger.LogInformation($"Network type: {networkType}");
            NetworkProvider = new NRustLightningNetworkProvider(networkType);
            var defaultSettings = NRustLightningDefaultSettings.GetDefaultSettings(NetworkProvider.NetworkType);

            DataDir = config.GetOrDefault <string>("datadir", null);
            if (DataDir is null)
            {
                DataDir = Path.GetDirectoryName(defaultSettings.DefaultDataDir);
                if (!Directory.Exists(DataDir))
                {
                    Directory.CreateDirectory(DataDir);
                }
                if (!Directory.Exists(defaultSettings.DefaultDataDir))
                {
                    Directory.CreateDirectory(defaultSettings.DefaultDataDir);
                }
            }

            var nbxConfig     = config.GetSection("nbx");
            var nbxCookieFile =
                nbxConfig.GetOrDefault("cookiefile",
                                       Constants.DefaultNBXplorerCookieFile(NetworkProvider.NetworkType));

            NBXplorerUri = new Uri(nbxConfig.GetOrDefault("rpcurl", Constants.DefaultNBXplorerUri));

            if (!File.Exists(nbxCookieFile))
            {
                logger.LogWarning($"cookie file for nbxplorer does not exist in {nbxCookieFile}" +
                                  " Make sure you are running nbx with --noauth.");
            }

            logger.LogInformation($"nbxplorer url {NBXplorerUri}");
            NBXCookieFile = nbxCookieFile;

            var p2pExternalIp = config.GetOrDefault("externalip", Constants.DefaultP2PExternalIpStr);

            if (IPEndPoint.TryParse(p2pExternalIp, out var ip))
            {
                P2PExternalIp = ip;
            }
            else if (p2pExternalIp.Contains(":"))
            {
                var s = p2pExternalIp.Split(":", StringSplitOptions.RemoveEmptyEntries);
                if (s.Length != 2)
                {
                    throw new ConfigException($"Invalid external ip {p2pExternalIp}");
                }

                if (Int32.TryParse(s[1], out var port))
                {
                    P2PExternalIp = new DnsEndPoint(s[0], port);
                }
                else
                {
                    throw new ConfigException($"Invalid external ip {p2pExternalIp}");
                }
            }
            else
            {
                throw new ConfigException($"Invalid external ip {p2pExternalIp}");
            }

            logger.LogInformation($"Advertising external ip: {P2PExternalIp.ToEndpointString()}");
            logger.LogDebug($"Network: {NetworkProvider.NetworkType.ToString()}");
            var supportedChains = config.GetOrDefault <string>("chains", "BTC")
                                  .Split(',', StringSplitOptions.RemoveEmptyEntries)
                                  .Select(t => t.ToLowerInvariant());
            var validChains = new List <string>();

            foreach (var n in NetworkProvider.GetAll())
            {
                if (supportedChains.Contains(n.CryptoCode))
                {
                    validChains.Add(n.CryptoCode);
                    var chainConfiguration = new ChainConfiguration();
                    chainConfiguration.CryptoCode = n.CryptoCode;
                    var args = RPCArgs.Parse(config, n.NBitcoinNetwork, n.CryptoCode);
                    chainConfiguration.Rpc = args.ConfigureRPCClient(n, logger);
                    if (chainConfiguration.Rpc.Address.Port == n.NBitcoinNetwork.DefaultPort)
                    {
                        logger.LogWarning($"{n.CryptoCode}: It seems that the1 RPC port ({chainConfiguration.Rpc.Address.Port}) is equal to the default P2P port ({n.NBitcoinNetwork.DefaultPort}, this is probably a misconfiguration)");
                    }
                    if ((chainConfiguration.Rpc.CredentialString.CookieFile != null || chainConfiguration.Rpc.CredentialString.UseDefault) && !n.SupportCookieAuthentication)
                    {
                        throw new ConfigException($"Chain {n.CryptoCode} does not support cookie file authentication,\n" +
                                                  $"Please use {n.CryptoCode.ToLowerInvariant()}rpcuser and {n.CryptoCode.ToLowerInvariant()}rpcpassword settings in NRustLightning" +
                                                  $"And configure rpcuser and rpcpassword in the configuration file or in commandline or your node");
                    }
                    ChainConfiguration.Add(chainConfiguration);
                }
            }
            var invalidChains = String.Join(',', supportedChains.Where(s => !validChains.Contains(s)));

            if (!string.IsNullOrEmpty(invalidChains))
            {
                throw new ConfigException($"Invalid chains {invalidChains}");
            }

            config.GetSection("ln").Bind(RustLightningConfig);

            string?seed     = null;
            var    filePath = Path.Join(DataDir, "node_secret");

            if (File.Exists(filePath))
            {
                logger.LogDebug($"reading seed from {filePath}");
                seed = File.ReadAllText(filePath);
            }
            if (seed is null)
            {
                seed = config.GetOrDefault("seed", String.Empty);
            }
            if (String.IsNullOrEmpty(seed))
            {
                logger.LogWarning($"seed not found in {filePath}! You can specify it with --seed option.");
                logger.LogInformation("generating new seed...");
                seed = RandomUtils.GetUInt256().ToString();
            }

            InvoiceDBFilePath = Path.Combine(DataDir, "InvoiceDb");
            if (!Directory.Exists(InvoiceDBFilePath))
            {
                Directory.CreateDirectory(InvoiceDBFilePath);
            }

            var h = new HexEncoder();

            if (!(h.IsValid(seed) && seed.Length == 64))
            {
                throw new NRustLightningException($"Seed corrupted {seed}");
            }
            File.WriteAllText(filePath, seed);
            GetSeed = async() => {
                var s = await File.ReadAllTextAsync(filePath);

                return(h.DecodeData(s));
            };

            PaymentTimeoutSec = config.GetOrDefault("paymenttimeout", Constants.DefaultPaymentTimeoutSec);

            DBCacheMB = config.GetOrDefault("dbcache", Constants.DefaultDBCacheMB);
            return(this);
        }
예제 #9
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery call hold example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.
            bool isCallHungup  = false;
            bool hasCallFailed = false;

            AddConsoleLogger();

            // Check whether an override desination has been entered on the command line.
            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            if (args != null && args.Length > 0)
            {
                if (!SIPURI.TryParse(args[0]))
                {
                    Log.LogWarning($"Command line argument could not be parsed as a SIP URI {args[0]}");
                }
                else
                {
                    callUri = SIPURI.ParseSIPURIRelaxed(args[0]);
                }
            }
            Log.LogInformation($"Call destination {callUri}.");

            // Set up a default SIP transport.
            _sipTransport = new SIPTransport();
            _sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, 0)));

            EnableTraceLogs(_sipTransport);

            var lookupResult = SIPDNSManager.ResolveSIPService(callUri, false);

            Log.LogDebug($"DNS lookup result for {callUri}: {lookupResult?.GetSIPEndPoint()}.");
            var dstAddress = lookupResult.GetSIPEndPoint().Address;

            IPAddress localIPAddress = NetServices.GetLocalAddressForRemote(dstAddress);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            _ourRtpSocket = null;
            Socket controlSocket = null;

            NetServices.CreateRtpSocket(localIPAddress, 48000, 48100, false, out _ourRtpSocket, out controlSocket);
            var rtpRecvSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);
            var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

            _ourSDP = GetSDP(_ourRtpSocket.LocalEndPoint as IPEndPoint, RTP_ATTRIBUTE_SENDRECV);

            // Create a client/server user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var userAgent = new SIPUserAgent(_sipTransport, null);

            userAgent.ClientCallTrying += (uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            };
            userAgent.ClientCallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            userAgent.ClientCallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
                exitCts.Cancel();
            };
            userAgent.ClientCallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    // Only set the remote RTP end point if there hasn't already been a packet received on it.
                    if (_remoteRtpEndPoint == null)
                    {
                        _remoteRtpEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);
                        Log.LogDebug($"Remote RTP socket {_remoteRtpEndPoint}.");
                    }
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };
            userAgent.CallHungup += () =>
            {
                Log.LogInformation($"Call hungup by remote party.");
                exitCts.Cancel();
            };
            userAgent.OnReinviteRequest += ReinviteRequestReceived;

            // The only incoming requests that need to be explicitly in this example program are in-dialog
            // re-INVITE requests that are being used to place the call on/off hold.
            _sipTransport.SIPTransportRequestReceived += (localSIPEndPoint, remoteEndPoint, sipRequest) =>
            {
                try
                {
                    if (sipRequest.Header.From != null &&
                        sipRequest.Header.From.FromTag != null &&
                        sipRequest.Header.To != null &&
                        sipRequest.Header.To.ToTag != null)
                    {
                        userAgent.InDialogRequestReceivedAsync(sipRequest).Wait();
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.OPTIONS)
                    {
                        SIPResponse optionsResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        _sipTransport.SendResponse(optionsResponse);
                    }
                }
                catch (Exception excp)
                {
                    Log.LogError($"Exception processing request. {excp.Message}");
                }
            };

            // It's a good idea to start the RTP receiving socket before the call request is sent.
            // A SIP server will generally start sending RTP as soon as it has processed the incoming call request and
            // being ready to receive will stop any ICMP error response being generated.
            Task.Run(() => RecvRtp(_ourRtpSocket, rtpRecvSession, exitCts));
            Task.Run(() => SendRtp(_ourRtpSocket, rtpSendSession, exitCts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIP_USERNAME,
                SIP_PASSWORD,
                callUri.ToString(),
                $"sip:{SIP_USERNAME}@localhost",
                callUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                _ourSDP.ToString(),
                null);

            userAgent.Call(callDescriptor);

            // At this point the call has been initiated and everything will be handled in an event handler.
            Task.Run(() =>
            {
                try
                {
                    while (!exitCts.Token.WaitHandle.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();
                        if (keyProps.KeyChar == 'h')
                        {
                            // Place call on/off hold.
                            if (userAgent.IsAnswered)
                            {
                                if (_holdStatus == HoldStatus.None)
                                {
                                    Log.LogInformation("Placing the remote call party on hold.");
                                    _holdStatus = HoldStatus.WePutOnHold;
                                    _ourSDP     = GetSDP(_ourRtpSocket.LocalEndPoint as IPEndPoint, RTP_ATTRIBUTE_SENDONLY);
                                    userAgent.SendReInviteRequest(_ourSDP);
                                }
                                else if (_holdStatus == HoldStatus.WePutOnHold)
                                {
                                    Log.LogInformation("Removing the remote call party from hold.");
                                    _holdStatus = HoldStatus.None;
                                    _ourSDP     = GetSDP(_ourRtpSocket.LocalEndPoint as IPEndPoint, RTP_ATTRIBUTE_SENDRECV);
                                    userAgent.SendReInviteRequest(_ourSDP);
                                }
                                else
                                {
                                    Log.LogInformation("Sorry we're already on hold by the remote call party.");
                                }
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            _ourRtpSocket?.Close();
            controlSocket?.Close();

            if (!isCallHungup && userAgent != null)
            {
                if (userAgent.IsAnswered)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (_sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                _sipTransport.Shutdown();
            }

            #endregion
        }
예제 #10
0
 public void Warn(Exception?exception, string message, params object[] args)
 {
     _logger.LogWarning(exception, message, args);
 }
예제 #11
0
        async void OnConnectButtonClicked(object sender, EventArgs args)
        {
            logger.LogDebug($"Attempting to connection to web socket at {this._webSocketURL.Text}.");

            var clientWebSocket = new ClientWebSocket();

            if (!Uri.TryCreate(this._webSocketURL.Text, UriKind.Absolute, out var uri))
            {
                this._status.Text = "Invalid web socket URI.";
            }
            else
            {
                this._connectButton.IsVisible = false;
                this._closeButton.IsVisible   = true;

                this._status.Text = "Attempting to connect to web socket server.";

                await clientWebSocket.ConnectAsync(uri, CancellationToken.None);

                var buffer   = WebSocket.CreateClientBuffer(8192, 8192);
                int attempts = 0;

                while (true && attempts < 10)
                {
                    WebSocketReceiveResult response = await clientWebSocket.ReceiveAsync(buffer, CancellationToken.None);

                    if (response.EndOfMessage)
                    {
                        _peer = new WebRTCPeer("peer1", DATA_CHANNEL_LABEL);

                        _peer.PeerConnection.oniceconnectionstatechange += (state) => Device.BeginInvokeOnMainThread(() => this._status.Text = $"ICE connection state {state}.");
                        _peer.PeerConnection.onconnectionstatechange    += (state) => Device.BeginInvokeOnMainThread(() => this._status.Text = $"Peer connection state {state}.");
                        _peer.OnDataChannelMessage += (msg_) => Device.BeginInvokeOnMainThread(() => this._dataChannelMessages.Text += $"\n{msg_}");

                        var options = new JsonSerializerOptions();
                        options.Converters.Add(new JsonStringEnumConverter());
                        var init = JsonSerializer.Deserialize <RTCSessionDescriptionInit>(buffer.Take(response.Count).ToArray(), options);
                        _peer.PeerConnection.setRemoteDescription(init);

                        var answer = _peer.PeerConnection.createAnswer(null);
                        await _peer.PeerConnection.setLocalDescription(answer);

                        var answerJson = JsonSerializer.Serialize <RTCSessionDescriptionInit>(answer, options);
                        await clientWebSocket.SendAsync(
                            new ArraySegment <byte>(System.Text.Encoding.UTF8.GetBytes(answerJson)),
                            WebSocketMessageType.Text, true, CancellationToken.None);

                        attempts = 10;
                        while (_peer.PeerConnection.connectionState == RTCPeerConnectionState.connecting && attempts < 10)
                        {
                            await Task.Delay(1000);

                            attempts++;
                        }

                        break;
                    }
                    else
                    {
                        logger.LogWarning("Failed to get full web socket message from server.");

                        this._status.Text = "Web socket message exchange failed.";
                    }

                    attempts++;
                }
            }
        }
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddLogging(loggingBuilder =>
                                loggingBuilder.AddSerilog(dispose: true));

            var sharedAssembly = typeof(CourseDetailsViewComponent).GetTypeInfo().Assembly;

            var cookieSecurePolicy = _env.IsDevelopment() ? CookieSecurePolicy.SameAsRequest : CookieSecurePolicy.Always;

            services.AddMvc(options =>
                            options.Filters.Add(typeof(McExceptionFilter))
                            )
            .ConfigureApplicationPartManager(apm =>
            {
                var apiClientAssembly = typeof(GovUk.Education.ManageCourses.ApiClient.ManageCoursesApiClient).GetTypeInfo().Assembly.GetName().Name;
                var api = typeof(GovUk.Education.ManageCourses.Api.Startup).GetTypeInfo().Assembly.GetName().Name;
                var dependentLibraries = apm.ApplicationParts.Where(x => x.Name == api || x.Name == apiClientAssembly).ToList();

                foreach (var item in dependentLibraries)
                {
                    apm.ApplicationParts.Remove(item);
                }
            }).AddCookieTempDataProvider(options => {
                options.Cookie.SecurePolicy = cookieSecurePolicy;
            })
            .AddApplicationPart(sharedAssembly);

            services.Configure <RazorViewEngineOptions>(o => o.FileProviders.Add(new EmbeddedFileProvider(sharedAssembly, "GovUk.Education.SearchAndCompare.UI.Shared")));

            services.AddRouting(options => options.LowercaseUrls = true);

            services.AddAntiforgery(options => {
                options.Cookie.SecurePolicy = cookieSecurePolicy;
            });
            services.AddAuthentication(options =>
            {
                options.DefaultSignInScheme       = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = OpenIdConnectDefaults.AuthenticationScheme;
            }).AddCookie(options =>
            {
                options.ExpireTimeSpan = TimeSpan.FromHours(6);
                options.Events         = new CookieAuthenticationEvents
                {
                    // refer to
                    //  https://github.com/mderriey/TokenRenewal
                    //  https://stackoverflow.com/questions/40032851/how-to-handle-expired-access-token-in-asp-net-core-using-refresh-token-with-open
                    // for more details

                    // this event is fired everytime the cookie has been validated by the cookie middleware,
                    // so basically during every authenticated request
                    // the decryption of the cookie has already happened so we have access to the user claims
                    // and cookie properties - expiration, etc..
                    OnValidatePrincipal = async x =>
                    {
                        // since our cookie lifetime is based on the access token one,
                        // check if we're more than halfway of the cookie lifetime
                        // assume a timeout of 20 minutes.
                        var timeElapsed = DateTimeOffset.UtcNow.Subtract(x.Properties.IssuedUtc.Value);

                        if (timeElapsed > TimeSpan.FromMinutes(19.5))
                        {
                            var identity          = (ClaimsIdentity)x.Principal.Identity;
                            var accessTokenClaim  = identity.FindFirst("access_token");
                            var refreshTokenClaim = identity.FindFirst("refresh_token");

                            // if we have to refresh, grab the refresh token from the claims, and request
                            // new access token and refresh token
                            var refreshToken = refreshTokenClaim.Value;

                            var clientId = Configuration["auth:oidc:clientId"];
                            const string envKeyClientSecret = "DFE_SIGNIN_CLIENT_SECRET";
                            var clientSecret = Configuration[envKeyClientSecret];
                            if (string.IsNullOrWhiteSpace(clientSecret))
                            {
                                throw new Exception("Missing environment variable " + envKeyClientSecret + " - get this from the DfE Sign-in team.");
                            }
                            var tokenEndpoint = Configuration["auth:oidc:tokenEndpoint"];

                            var client   = new TokenClient(tokenEndpoint, clientId, clientSecret);
                            var response = await client.RequestRefreshTokenAsync(refreshToken, new { client_secret = clientSecret });

                            if (!response.IsError)
                            {
                                // everything went right, remove old tokens and add new ones
                                identity.RemoveClaim(accessTokenClaim);
                                identity.RemoveClaim(refreshTokenClaim);

                                identity.AddClaims(new[]
                                {
                                    new Claim("access_token", response.AccessToken),
                                    new Claim("refresh_token", response.RefreshToken)
                                });

                                // indicate to the cookie middleware to renew the session cookie
                                // the new lifetime will be the same as the old one, so the alignment
                                // between cookie and access token is preserved
                                x.ShouldRenew = true;
                            }
                            else
                            {
                                // could not refresh - log the user out
                                _logger.LogWarning("Token refresh failed with message: " + response.ErrorDescription);
                                x.RejectPrincipal();
                            }
                        }
                    }
                };
            }).AddOpenIdConnect(options =>
            {
                options.SignInScheme    = CookieAuthenticationDefaults.AuthenticationScheme;
                options.MetadataAddress = Configuration["auth:oidc:metadataAddress"];

                options.ClientId = Configuration["auth:oidc:clientId"];
                const string envKeyClientSecret = "DFE_SIGNIN_CLIENT_SECRET";
                var clientSecret = Configuration[envKeyClientSecret];
                if (string.IsNullOrWhiteSpace(clientSecret))
                {
                    throw new Exception("Missing environment variable " + envKeyClientSecret + " - get this from the DfE Sign-in team.");
                }

                options.ClientSecret = clientSecret;
                options.ResponseType = OpenIdConnectResponseType.Code;
                options.GetClaimsFromUserInfoEndpoint = true;

                // using this property would align the expiration of the cookie
                // with the expiration of the identity token
                // UseTokenLifetime = true;

                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("email");
                options.Scope.Add("profile");

                options.Scope.Add("offline_access");

                options.SaveTokens             = true;
                options.CallbackPath           = new PathString(Configuration["auth:oidc:callbackPath"]);
                options.SignedOutCallbackPath  = new PathString(Configuration["auth:oidc:signedOutCallbackPath"]);
                options.SecurityTokenValidator = new JwtSecurityTokenHandler
                {
                    InboundClaimTypeMap            = new Dictionary <string, string>(),
                    TokenLifetimeInMinutes         = 20,
                    SetDefaultTimesOnTokenCreation = true,
                };
                options.ProtocolValidator = new OpenIdConnectProtocolValidator
                {
                    RequireSub             = true,
                    RequireStateValidation = false,
                    NonceLifetime          = TimeSpan.FromMinutes(15)
                };

                options.DisableTelemetry = true;
                options.Events           = new OpenIdConnectEvents
                {
                    // Sometimes, problems in the OIDC provider (such as session timeouts)
                    // Redirect the user to the /auth/cb endpoint. ASP.NET Core middleware interprets this by default
                    // as a successful authentication and throws in surprise when it doesn't find an authorization code.
                    // This override ensures that these cases redirect to the root.
                    OnMessageReceived = context =>
                    {
                        var isSpuriousAuthCbRequest =
                            context.Request.Path == options.CallbackPath &&
                            context.Request.Method == "GET" &&
                            !context.Request.Query.ContainsKey("code");

                        if (isSpuriousAuthCbRequest)
                        {
                            context.HandleResponse();
                            context.Response.StatusCode          = 302;
                            context.Response.Headers["Location"] = "/";
                        }

                        return(Task.CompletedTask);
                    },

                    // Sometimes the auth flow fails. The most commonly observed causes for this are
                    // Cookie correlation failures, caused by obscure load balancing stuff.
                    // In these cases, rather than send user to a 500 page, prompt them to re-authenticate.
                    // This is derived from the recommended approach: https://github.com/aspnet/Security/issues/1165
                    OnRemoteFailure = ctx =>
                    {
                        ctx.Response.Redirect("/");
                        ctx.HandleResponse();
                        return(Task.FromResult(0));
                    },

                    OnRedirectToIdentityProvider = context =>
                    {
                        context.ProtocolMessage.Prompt = "consent";
                        return(Task.CompletedTask);
                    },

                    // that event is called after the OIDC middleware received the auhorisation code,
                    // redeemed it for an access token and a refresh token,
                    // and validated the identity token
                    OnTokenValidated = x =>
                    {
                        // store both access and refresh token in the claims - hence in the cookie
                        var identity = (ClaimsIdentity)x.Principal.Identity;
                        identity.AddClaims(new[]
                        {
                            new Claim("access_token", x.TokenEndpointResponse.AccessToken),
                            new Claim("refresh_token", x.TokenEndpointResponse.RefreshToken)
                        });

                        // so that we don't issue a session cookie but one with a fixed expiration
                        x.Properties.IsPersistent = true;

                        return(Task.CompletedTask);
                    }
                };
            });
            services.AddScoped <SearchAndCompare.UI.Shared.Features.IFeatureFlags, SearchAndCompare.UI.Shared.Features.FeatureFlags>();
            services.AddSingleton <ISearchAndCompareUrlService>(x => new SearchAndCompareUrlService(Configuration.GetValue("SearchAndCompare:UiBaseUrl", "")));
            services.AddSingleton <IFrontendUrlService, FrontendUrlService>();
            services.AddSingleton <IHttpClient>(serviceProvider => {
                var httpContextAccessor = serviceProvider.GetService <IHttpContextAccessor>();


                return(new ManageCoursesApiHttpClientWrapper(httpContextAccessor, new HttpClient()));
            });
            services.AddScoped(provider => AnalyticsPolicy.FromEnv());
            services.AddScoped <AnalyticsAttribute>();
            services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton <ManageCoursesConfig, ManageCoursesConfig>();
            services.AddSingleton <IManageApi, ManageApi>();
            services.AddSingleton <ITelemetryInitializer, SubjectTelemetryInitialiser>();
            services.AddApplicationInsightsTelemetry();

            services.AddSingleton(serviceProvider =>
            {
                var clientWrapper          = serviceProvider.GetService <IHttpClient>();
                var config                 = serviceProvider.GetService <ManageCoursesConfig>();
                var manageCoursesApiClient = new ManageCoursesApiClient(config.ApiUrl, clientWrapper);
                return(manageCoursesApiClient);
            });
        }
예제 #13
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery call hold example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            AddConsoleLogger();

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            EnableTraceLogs(sipTransport);

            // Create two user agents. Each gets configured to answer an incoming call.
            var userAgent1 = new SIPUserAgent(sipTransport, null);
            var userAgent2 = new SIPUserAgent(sipTransport, null);

            // Only one of the user agents can use the microphone and speaker. The one designated
            // as the active agent gets the devices.
            SIPUserAgent    activeUserAgent  = null;
            RTPMediaSession activeRtpSession = null;

            // Get the default speaker.
            var(audioOutEvent, audioOutProvider) = GetAudioOutputDevice();
            m_audioOutProvider = audioOutProvider;
            WaveInEvent waveInEvent = GetAudioInputDevice();

            userAgent1.OnCallHungup        += () => Log.LogInformation($"UA1: Call hungup by remote party.");
            userAgent1.ServerCallCancelled += (uas) => Log.LogInformation("UA1: Incoming call cancelled by caller.");

            userAgent2.OnCallHungup        += () => Log.LogInformation($"UA2: Call hungup by remote party.");
            userAgent2.ServerCallCancelled += (uas) => Log.LogInformation("UA2: Incoming call cancelled by caller.");

            userAgent2.OnTransferNotify += (sipFrag) =>
            {
                if (!string.IsNullOrEmpty(sipFrag))
                {
                    Log.LogInformation($"UA2: Transfer status update: {sipFrag.Trim()}.");
                    if (sipFrag?.Contains("SIP/2.0 200") == true)
                    {
                        // The transfer attempt got a succesful answer. Can hangup the call.
                        userAgent2.Hangup();
                        exitCts.Cancel();
                    }
                }
            };

            sipTransport.SIPTransportRequestReceived += (locelEndPoint, remoteEndPoint, sipRequest) =>
            {
                if (sipRequest.Header.From != null &&
                    sipRequest.Header.From.FromTag != null &&
                    sipRequest.Header.To != null &&
                    sipRequest.Header.To.ToTag != null)
                {
                    // This is an in-dialog request that will be handled directly by a user agent instance.
                }
                else if (sipRequest.Method == SIPMethodsEnum.INVITE)
                {
                    if (!userAgent1.IsCallActive)
                    {
                        Log.LogInformation($"UA1: Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        var incomingCall = userAgent1.AcceptCall(sipRequest);

                        var rtpMediaSession = new RTPMediaSession(SDPMediaTypesEnum.audio, new SDPMediaFormat(SDPMediaFormatsEnum.PCMU), AddressFamily.InterNetwork);
                        rtpMediaSession.RemotePutOnHold   += () => Log.LogInformation("UA1: Remote call party has placed us on hold.");
                        rtpMediaSession.RemoteTookOffHold += () => Log.LogInformation("UA1: Remote call party took us off hold.");

                        userAgent1.Answer(incomingCall, rtpMediaSession)
                        .ContinueWith(task =>
                        {
                            activeUserAgent  = userAgent1;
                            activeRtpSession = rtpMediaSession;
                            activeRtpSession.OnRtpPacketReceived += PlaySample;
                            waveInEvent.StartRecording();

                            Log.LogInformation($"UA1: Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}.");
                        }, exitCts.Token);
                    }
                    else if (!userAgent2.IsCallActive)
                    {
                        Log.LogInformation($"UA2: Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");

                        var incomingCall    = userAgent2.AcceptCall(sipRequest);
                        var rtpMediaSession = new RTPMediaSession(SDPMediaTypesEnum.audio, new SDPMediaFormat(SDPMediaFormatsEnum.PCMU), AddressFamily.InterNetwork);
                        rtpMediaSession.RemotePutOnHold   += () => Log.LogInformation("UA2: Remote call party has placed us on hold.");
                        rtpMediaSession.RemoteTookOffHold += () => Log.LogInformation("UA2: Remote call party took us off hold.");

                        userAgent2.Answer(incomingCall, rtpMediaSession)
                        .ContinueWith(task =>
                        {
                            activeRtpSession.OnRtpPacketReceived -= PlaySample;

                            activeUserAgent  = userAgent2;
                            activeRtpSession = rtpMediaSession;
                            activeRtpSession.PutOnHold();
                            activeRtpSession.OnRtpPacketReceived += PlaySample;

                            Log.LogInformation($"UA2: Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}.");
                        }, exitCts.Token);
                    }
                    else
                    {
                        // If both user agents are already on a call return a busy response.
                        Log.LogWarning($"Busy response returned for incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                        SIPResponse          busyResponse   = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BusyHere, null);
                        uasTransaction.SendFinalResponse(busyResponse);
                    }
                }
                else
                {
                    Log.LogDebug($"SIP {sipRequest.Method} request received but no processing has been set up for it, rejecting.");
                    SIPResponse notAllowedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                    return(sipTransport.SendResponseAsync(notAllowedResponse));
                }

                return(Task.FromResult(0));
            };

            // Wire up the RTP send session to the audio input device.
            uint rtpSendTimestamp = 0;

            waveInEvent.DataAvailable += (object sender, WaveInEventArgs args) =>
            {
                byte[] sample      = new byte[args.Buffer.Length / 2];
                int    sampleIndex = 0;

                for (int index = 0; index < args.BytesRecorded; index += 2)
                {
                    var ulawByte = NAudio.Codecs.MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(args.Buffer, index));
                    sample[sampleIndex++] = ulawByte;
                }

                if (activeRtpSession != null)
                {
                    activeRtpSession.SendAudioFrame(rtpSendTimestamp, (int)SDPMediaFormatsEnum.PCMU, sample);
                    rtpSendTimestamp += (uint)sample.Length;
                }
            };

            // At this point the call has been initiated and everything will be handled in an event handler.
            Task.Run(async() =>
            {
                try
                {
                    while (!exitCts.Token.WaitHandle.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();

                        if (keyProps.KeyChar == 't')
                        {
                            if (userAgent1.IsCallActive && userAgent2.IsCallActive)
                            {
                                bool result = await userAgent2.AttendedTransfer(userAgent1.Dialogue, TimeSpan.FromSeconds(TRANSFER_TIMEOUT_SECONDS), exitCts.Token);
                                if (!result)
                                {
                                    Log.LogWarning($"Attended transfer failed.");
                                }
                            }
                            else
                            {
                                Log.LogWarning("There need to be two active calls before the attended transfer can occur.");
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            userAgent1?.Hangup();
            userAgent2?.Hangup();
            waveInEvent?.StopRecording();
            audioOutEvent?.Stop();

            // Give any BYE or CANCEL requests time to be transmitted.
            Log.LogInformation("Waiting 1s for calls to be cleaned up...");
            Task.Delay(1000).Wait();

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }

            #endregion
        }
예제 #14
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery Call Hold and Blind Transfer example.");
            Console.WriteLine("Press 'c' to initiate a call to the default destination.");
            Console.WriteLine("Press 'h' to place an established call on and off hold.");
            Console.WriteLine("Press 'H' to hangup an established call.");
            Console.WriteLine("Press 't' to request a blind transfer on an established call.");
            Console.WriteLine("Press 'q' or ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            AddConsoleLogger();

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            Console.WriteLine($"Listening for incoming calls on: {sipTransport.GetSIPChannels().First().ListeningEndPoint}.");

            EnableTraceLogs(sipTransport);

            _currentDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            RtpAVSession rtpAVSession = null;

            // Create a client/server user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var userAgent = new SIPUserAgent(sipTransport, null);

            userAgent.RemotePutOnHold   += () => Log.LogInformation("Remote call party has placed us on hold.");
            userAgent.RemoteTookOffHold += () => Log.LogInformation("Remote call party took us off hold.");

            sipTransport.SIPTransportRequestReceived += async(localEndPoint, remoteEndPoint, sipRequest) =>
            {
                if (sipRequest.Header.From != null &&
                    sipRequest.Header.From.FromTag != null &&
                    sipRequest.Header.To != null &&
                    sipRequest.Header.To.ToTag != null)
                {
                    // This is an in-dialog request that will be handled directly by a user agent instance.
                }
                else if (sipRequest.Method == SIPMethodsEnum.INVITE)
                {
                    if (userAgent?.IsCallActive == true)
                    {
                        Log.LogWarning($"Busy response returned for incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        // If we are already on a call return a busy response.
                        UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                        SIPResponse          busyResponse   = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BusyHere, null);
                        uasTransaction.SendFinalResponse(busyResponse);
                    }
                    else
                    {
                        Log.LogInformation($"Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        var incomingCall = userAgent.AcceptCall(sipRequest);

                        rtpAVSession = new RtpAVSession(new AudioOptions {
                            AudioSource = AudioSourcesEnum.CaptureDevice
                        }, null);
                        await userAgent.Answer(incomingCall, rtpAVSession);

                        Log.LogInformation($"Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}.");
                    }
                }
                else
                {
                    Log.LogDebug($"SIP {sipRequest.Method} request received but no processing has been set up for it, rejecting.");
                    SIPResponse notAllowedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                    await sipTransport.SendResponseAsync(notAllowedResponse);
                }
            };

            // At this point the call has been initiated and everything will be handled in an event handler.
            Task.Run(async() =>
            {
                try
                {
                    while (!exitCts.Token.WaitHandle.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();

                        if (keyProps.KeyChar == 'c')
                        {
                            if (!userAgent.IsCallActive)
                            {
                                rtpAVSession = new RtpAVSession(new AudioOptions {
                                    AudioSource = AudioSourcesEnum.CaptureDevice
                                }, null);
                                bool callResult = await userAgent.Call(DEFAULT_DESTINATION_SIP_URI, SIP_USERNAME, SIP_PASSWORD, rtpAVSession);

                                Log.LogInformation($"Call attempt {((callResult) ? "successfull" : "failed")}.");
                            }
                            else
                            {
                                Log.LogWarning("There is already an active call.");
                            }
                        }
                        else if (keyProps.KeyChar == 'h')
                        {
                            // Place call on/off hold.
                            if (userAgent.IsCallActive)
                            {
                                if (userAgent.IsOnLocalHold)
                                {
                                    Log.LogInformation("Taking the remote call party off hold.");
                                    userAgent.TakeOffHold();
                                    await(userAgent.MediaSession as RtpAVSession).SetSources(new AudioOptions {
                                        AudioSource = AudioSourcesEnum.CaptureDevice
                                    }, null);
                                }
                                else
                                {
                                    Log.LogInformation("Placing the remote call party on hold.");
                                    userAgent.PutOnHold();
                                    await(userAgent.MediaSession as RtpAVSession).SetSources(new AudioOptions
                                    {
                                        AudioSource = AudioSourcesEnum.Music,
                                        SourceFiles = new Dictionary <SDPMediaFormatsEnum, string>
                                        {
                                            { SDPMediaFormatsEnum.PCMU, _currentDir + "/" + AUDIO_FILE_PCMU }
                                        }
                                    }, null);
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to put on hold.");
                            }
                        }
                        else if (keyProps.KeyChar == 'H')
                        {
                            if (userAgent.IsCallActive)
                            {
                                Log.LogInformation("Hanging up call.");
                                userAgent.Hangup();
                            }
                        }
                        else if (keyProps.KeyChar == 't')
                        {
                            // Initiate a blind transfer to the remote call party.
                            if (userAgent.IsCallActive)
                            {
                                var transferURI = SIPURI.ParseSIPURI(TRANSFER_DESTINATION_SIP_URI);
                                bool result     = await userAgent.BlindTransfer(transferURI, TimeSpan.FromSeconds(TRANSFER_TIMEOUT_SECONDS), exitCts.Token);
                                if (result)
                                {
                                    // If the transfer was accepted the original call will already have been hungup.
                                    // Wait a second for the transfer NOTIFY request to arrive.
                                    await Task.Delay(1000);
                                    exitCts.Cancel();
                                }
                                else
                                {
                                    Log.LogWarning($"Transfer to {TRANSFER_DESTINATION_SIP_URI} failed.");
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to transfer.");
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            rtpAVSession?.Close("app exit");

            if (userAgent != null)
            {
                if (userAgent.IsCallActive)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }

            #endregion
        }
예제 #15
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        // Configure is called after ConfigureServices is called.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            //loggerFactory.MinimumLevel = LogLevel.Information;
            // root min level: you have to set this the most detailed, because if not ASPlog will not pass it to the NLogExtension
            loggerFactory.MinimumLevel = Microsoft.Extensions.Logging.LogLevel.Debug;

            // A. ASP.NET5 LogLevels can come from appsettings.json or set here programmatically. But Configuration.GetSection("") returns text from the file,
            // and not the file itself, so ConsoleLogger is not able to reload config when appsettings.json file is changed.
            // For that you need a FileSystem watcher manually, which is not OK on Linux systems I guess or not on DNXCore
            // Therefore logging level cannot be changed by modifying that file (at least, not without extra FileSystemWatcher programming)
            // B. On the other hand Nlog is based on DNX, not DNXCore, and implements FileSystemWatcher properly, and I tested it and
            // when the app.nlog file is changed by Notepad nLog under Asp.NET notices the LogLevelChange.
            loggerFactory.AddConsole(Configuration.GetSection("LoggingToConsole"));
            //loggerFactory.AddConsole(LogLevel.Debug);     // write to the Console  (if available) window as Colorful multiline (in Kestrel??) . MinLevel can be specified. by default it is LogLevel.Information
            loggerFactory.AddDebug(Microsoft.Extensions.Logging.LogLevel.Debug);       // write to the Debug output window (in VS). MinLevel can be specified. by default it is LogLevel.Information
            #if !DNXCORE50
            #if NlogInternalLoggingNeeded
            // nLog searches these config files in GetCandidateFileNames() (version nLog 3.1), later renamed to GetCandidateConfigFileNames()
            // NLog.config from application directory, "C:\\Users\\gyantal\\.dnx\\runtimes\\dnx-clr-win-x86.1.0.0-rc1-update1\\bin\\NLog.config"
            string standardCandidate = Path.Combine(NLog.LogFactory.CurrentAppDomain.BaseDirectory, "NLog.config");   // myExeFolder/Nlog.config
            // current config file with (EXE) .config renamed to .nlog, "g:\\work\\Archi-data\\GitHubRepos\\SQHealthMonitor\\src\\SQHealthMonitor\\app.nlog"
            string appDotNlog = Path.ChangeExtension(NLog.LogFactory.CurrentAppDomain.ConfigurationFile, ".nlog"); //myExeFolder/MyExe
            // get path to NLog.dll.nlog only if the assembly is not in the GAC, "C:\\Users\\gyantal\\.dnx\\packages\\NLog\\4.2.2\\lib\\net45\\NLog.dll.nlog"
            string dllDotNlog = typeof(NLog.LogFactory).Assembly.Location + ".nlog";

            NLog.Common.InternalLogger.LogLevel = NLog.LogLevel.Trace;  // this sets up from the default highLevel Info to detailed Trace; in order for Internal NLog logging to be Verbose
            NLog.Common.InternalLogger.LogToConsole = true;
            NLog.Common.InternalLogger.LogFile = @"g:\temp\nlogKestrel_InternalLogger.log";
            #endif
            //NLog.ILogger tempNlogLogger = LogManager.GetCurrentClassLogger();   //https://github.com/nlog/NLog/wiki/Configuration-file
            //SetNLogTableStorageConnectionString();
            //// when nlog.config is rewritten while the exe is running, AzureTableStorageConnectionString is lost
            //LogManager.ConfigurationReloaded += (sender, args) => { SetNLogTableStorageConnectionString(); };
            //tempNlogLogger.Info("This Logger created by LogManager() works properly under ASP.NET5. Writes proper AzuteStorageTable");

            //During Webserver runtime(Debugging in VS), file modification of app.nlog should not be done in VS2015, because
            //VS has a trick that it doesn't change file's Time under Debug, and so NLog.dll will not notice that this config file has been changed.
            //So, change this config file in NotePad.exe or TotalCommander, etc.
            NLog.LogFactory nlogLogFactory = new global::NLog.LogFactory();
            SetNLogTableStorageConnectionStringAndEmailSmtp(nlogLogFactory);
            // when nlog.config is rewritten while the exe is running, AzureTableStorageConnectionString is lost
            nlogLogFactory.ConfigurationReloaded += (sender, args) => { SetNLogTableStorageConnectionStringAndEmailSmtp(nlogLogFactory); };

            loggerFactory.AddProvider(new NLogLoggerProvider(nlogLogFactory));

            //nlogLogFactory.ConfigurationReloaded += (sender, args) => { SetNLogTableStorageConnectionString(); };
            //loggerFactory.AddNLog(nlogLogFactory);

            //loggerFactory.AddEventLog();  // probably Windows Eventlogs, implemented in Microsoft.Extensions.Logging.EventLog

            System.AppDomain.CurrentDomain.DomainUnload += (sender, args) => {
                Thread.Sleep(1);
                nlogLogFactory.Flush();
                LogManager.Flush();
            };
            System.AppDomain.CurrentDomain.ProcessExit += (sender, args) => {
                //Checked: when I shutdown the Webserver, by typing Ctrl-C, saying Initiate Webserver shutdown, this is called second after calling Dispose() of all IDispose objects
                Thread.Sleep(1);
                nlogLogFactory.Flush();
                LogManager.Flush();
            };
            System.AppDomain.CurrentDomain.UnhandledException += (sender, args) => {
                Thread.Sleep(1);
                nlogLogFactory.Flush();
                LogManager.Flush();
            };
            #endif

            mStartupLogger = loggerFactory.CreateLogger(typeof(Program).FullName);
            mStartupLogger.LogInformation("****START: Loggers are initialized in Startup.Configure()"); // high Level UserInfo
            #if !DNXCORE50

            ////Logger = LogManager.GetCurrentClassLogger();   //https://github.com/nlog/NLog/wiki/Configuration-file
            //SetNLogTableStorageConnectionString();
            //// when nlog.config is rewritten while the exe is running, AzureTableStorageConnectionString is lost
            //LogManager.ConfigurationReloaded += (sender, args) => { SetNLogTableStorageConnectionString(); };

            //var mStartupLogger2 = loggerFactory.CreateLogger(typeof(Program).FullName + "2");
            //mStartupLogger2.LogInformation("****creating mStartupLogger2 after setting ConnString."); // high Level UserInfo
            #endif

            //gStartupLogger.LogDebug("This is LogDebug() log info");  // most detailed, Trace in nLog
            //gStartupLogger.LogVerbose("This is LogVerbose() log info");  // normal-detailed, Debug in nLog
            //gStartupLogger.LogInformation("This is LogInformation() log info"); // high Level UserInfo

            // Add the platform handler to the request pipeline.
            app.UseIISPlatformHandler();    // : it is needed to resolve the Windows identity corresponding to the token flowed by IIS.

            if (env.IsDevelopment())
            {
                //app.UseDeveloperExceptionPage();
            }

            //Utils.InitSt();
            // Agy: I think this ASP5 solution is token based too. Just stores token in Cookies, which is perfect for a Browser based app like AngularJS
            //A. Conclusion: Storage user-token(not proper bearer token, but token) in cookies is good (in an AngularJS webApp, cookie storage is ideal.)
            //https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/
            //Conclusion: "Stormpath recommends that you store your JWT in cookies for web applications, because of the additional security they provide, and the simplicity of protecting against CSRF with modern web frameworks. HTML5 Web Storage (from here to Authentication Header) is vulnerable to XS"
            //> Basically, the caller of webServiceApi has to provide the userInfo.So, it has to store somewhere.
            //This article says: always use JWT Tokens. (ASP5 uses that, because it always send the full user info in the Cookies)
            //0.Browser based: Storing in Browser RAM in Javascript variable (from here to the "HTML Authentication header") is not good.Restart Browser Tab/Refresh will result => use has to log-in again.
            //1.Browser based: HTML5 WebStorage and from here to the "HTML Authentication header"
            //2.Browser based: cookie storage persistent too. Better.
            //3.Native App based: store in App memory, or in a file, etc. however you want.And use "HTML Authentication header" with the tokens.
            //B. ASP5 don't support yet the proper bearer tokens, but it doesn't matter.
            //https://en.wikipedia.org/wiki/Basic_access_authentication
            //https://developers.google.com/gmail/markup/actions/verifying-bearer-tokens
            //Bearer Tokens are part of the OAuth V2 standard and widely adopted by Google APIs.
            //// Agy: They will support it later. For now, I should forget it.
            //https://github.com/aspnet/Identity/search?q=Bearer&type=Issues&utf8=%E2%9C%93
            //https://github.com/aspnet/Identity/issues/495
            //In case anyone needs bearer tokens earlier.Basic example of Identity with Bearer tokens.
            //https://github.com/bigfont/AspNet.Security.OpenIdConnect.Server/tree/bigfont/samples/ResourceOwnerPasswordFlow
            //Probably later, this is a style how you should do it (for API calls, user-data should come from HTML header, from Browser user data should come from Cookie:
            //app.UseWhen(context => context.Request.Path.StartsWithSegments(new PathString("/api")), branch =>
            //{ branch.UseOAuthBearerAuthentication(options =>

            //string cId = Configuration["A:G:CId"], cSe = Configuration["A:G:CSe"];
            //string cId = Configuration["AppSettings:A_G_CId"], cSe = Configuration["AppSettings:A_G_CSe"];
            string cId = Configuration["A_G_CId"], cSe = Configuration["A_G_CSe"];
            if (!String.IsNullOrEmpty(cId) && !String.IsNullOrEmpty(cSe))
            {
                mStartupLogger.LogInformation("A_G_CId and A_G_CSe from Config has been found. Initializing GoogelAuthentication.");
                app.UseCookieAuthentication(options =>
                {
                    //options.LoginPath = "/account/login";
                    options.AuthenticationScheme = "Cookies";
                    options.AutomaticAuthenticate = true;
                    //options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
                    options.ExpireTimeSpan = TimeSpan.FromDays(10);
                    options.SlidingExpiration = false;
                });

                //// from official sample; name suggest it is token based, albeit it is not named Bearer; feeling: app.UseCookieAuthentication() is exactly this
                //app.UseOAuthAuthentication("Google-AccessToken", options =>
                //{
                //    options.AuthenticationScheme = "Google-AccessToken";
                //    //options.DisplayName = "Google-AccessToken",
                //    options.ClientId = Utils.g_YmVsYUJlbG92aXRz[0];
                //    options.ClientSecret = Utils.g_YmVsYUJlbG92aXRz[1];
                //    options.CallbackPath = new PathString("/signin-google-token");
                //    options.AuthorizationEndpoint = GoogleAuthenticationDefaults.AuthorizationEndpoint;
                //    options.TokenEndpoint = GoogleAuthenticationDefaults.TokenEndpoint;
                //    options.Scope.Add("https://www.googleapis.com/auth/plus.profile.emails.read");
                //});

                // this is from the official GitHub sample https://github.com/aspnet/Identity/blob/b9be30c6cdf055394eb5ca9cd95d02419fcdf4b4/samples/IdentitySample.Mvc/Startup.cs
                app.UseGoogleAuthentication(options =>
                {
                    options.ClientId = Encoding.UTF8.GetString(Convert.FromBase64String(cId));
                    options.ClientSecret = Encoding.UTF8.GetString(Convert.FromBase64String(cSe));

                    //options.SignInScheme = null; // by default, which doesn't work itself. It needs UseCookieAuthentication()
                    //options.SignInScheme = "Google-AccessToken"; // 2015-10-02: "System.NotSupportedException"; I guess later they will support it
                    options.SignInScheme = "Cookies";
                    options.AutomaticAuthenticate = true;  // this is false by default; if it is true, all [Authorize] Actions try to log-in to Google

                    // don't touch CallbackPath then: The CallbackPath is the google middleware callback, not the application callback. You set the application callback path on the RedirectUri property on the AuthenticationProperties that you pass when you call Challenge on the IAuthenticationManager
                    //options.CallbackPath = new PathString("/TestAuth/oauthcallback");   //new PathString("/signin-google"); is the default

                    // Scopes: Official Google page is here: https://developers.google.com/+/web/api/rest/oauth
                    // Robert uses this: { "scope", "https://www.googleapis.com/auth/plus.profile.emails.read" },  // as per stackoverflow.com/a/23764783 . Despite the docs (e.g. developers.google.com/+/api/oauth#login-scopes) suggest "email", that resulted in "this app would like to have offline access" after a couple of days
                    // http://stackoverflow.com/questions/24410179/is-there-a-way-to-only-get-a-users-email-address-with-googles-oauth2-impleme
                    // Conclusion: the First item: "Know who you are on Google" is always there. Cannot make it disappear. It is Google's policy.
                    options.Scope.Add("https://www.googleapis.com/auth/plus.profile.emails.read"); // George: Robert thinks it is better then "email", but it asked ""this app would like to have offline access"" too

                    //options.AuthenticationScheme = "Google"; // this is by default
                    //options.AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/auth"; // suggest token based, not cookie based
                });
            }
            else
            {
                mStartupLogger.LogWarning("A_G_CId and A_G_CSe from Config has NOT been found. Cannot initialize GoogelAuthentication.");
            }

            // Configure the HTTP request pipeline.
            app.UseStaticFiles();   // without it, the Server will not return static HTML files
            //app.UseDefaultFiles();
            //app.UseDefaultFiles(new Microsoft.AspNet.StaticFiles.DefaultFilesOptions() { DefaultFileNames = new[] { "Index.html" } });

            // Add MVC to the request pipeline.
            //app.UseMvc();
            //app.UseMvcWithDefaultRoute();  // following template: '{controller=Home}/{action=Index}/{id?}'.
            app.UseMvc(routes =>
             {
                 //routes.IgnoreRoute("");    //ignore empty routes //Re: Is there a workaround for routes.IgnoreRoute() in ASP.NET 5? (Method not implemented [yet])

                 // http://stackoverflow.com/questions/28017193/how-to-ignore-routes-in-mvc6
                 //routes.MapRoute(
                 //   name: "RootHomepage",
                 //   template: "",   // empty Route Should go to Index.html
                 //   defaults: new { controller = "RootHomepageRedirect", action = "Index" });

                 routes.MapRoute(
                    name: "route1",
                    template: "DeveloperDashboardForLocalDevelopment",
                    defaults: new { controller = "RootHomepageRedirect", action = "DeveloperDashboardForLocalDevelopment" }
                );
                routes.MapRoute(
                    name: "route2",
                    template: "UserDashboardForLocalDevelopment",
                    defaults: new { controller = "RootHomepageRedirect", action = "UserDashboardForLocalDevelopment" }
                );

                 routes.MapRoute(
                    name: "route3",
                    template: "DeveloperDashboard",
                    defaults: new { controller = "RootHomepageRedirect", action = "DeveloperDashboard" }
                );
                 routes.MapRoute(
                     name: "default",
                     template: "{controller}/{action}/{id?}",   // this is needed for Controller methods as Actions to be subPath items in URL
                     defaults: new { controller = "RootHomepageRedirect", action = "Index" });
             });

            // Add the following route for porting Web API 2 controllers.
            // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
        }
예제 #16
0
파일: Startup.cs 프로젝트: kant/embc-ess
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // add singleton to allow Controllers to query the Request object
            services
            .AddSingleton <IHttpContextAccessor, HttpContextAccessor>()
            .AddSingleton(configuration)
            .AddDbContext <EmbcDbContext>(
                options => options
                .UseLoggerFactory(loggerFactory)
                .UseSqlServer(DatabaseTools.GetConnectionString(configuration))
                )
            // CORS policy
            .AddCors(opts =>
            {
                opts.AddDefaultPolicy(builder =>
                {
                    builder.WithOrigins(
                        "http://pathfinder.bcgov",
                        "https://*.pathfinder.gov.bc.ca",
                        "https://dev.justice.gov.bc.ca",
                        "https://test.justice.gov.bc.ca",
                        "https://justice.gov.bc.ca")
                    .SetIsOriginAllowedToAllowWildcardSubdomains();
                });
            })
            //XSRF token for Angular - not working yet
            //.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN")
            .AddMvc(opts =>
            {
                // anti forgery validation by default - not working yet
                //opts.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
            })
            .AddJsonOptions(
                opts =>
            {
                opts.SerializerSettings.Formatting            = Newtonsoft.Json.Formatting.Indented;
                opts.SerializerSettings.DateFormatHandling    = Newtonsoft.Json.DateFormatHandling.IsoDateFormat;
                opts.SerializerSettings.DateTimeZoneHandling  = Newtonsoft.Json.DateTimeZoneHandling.Utc;
                opts.SerializerSettings.DateParseHandling     = Newtonsoft.Json.DateParseHandling.DateTimeOffset;
                opts.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            });

            // Register the Swagger services
            services.AddSwaggerDocument(config =>
            {
                config.PostProcess = document =>
                {
                    document.Info.Version     = "v1";
                    document.Info.Title       = "ESS API";
                    document.Info.Description = "Emergency Management BC Evacuee Support System API";
                };
            }
                                        );

            services.AddScoped <KeyCloakClaimTransformer, KeyCloakClaimTransformer>();
            services.AddAuthentication(options =>
            {
                //Default to cookie auth, challenge with OIDC
                options.DefaultScheme          = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                options.DefaultSignInScheme    = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            //JWT bearer to support direct API authentication
            .AddJwtBearer(options =>
            {
                configuration.GetSection("auth:jwt").Bind(options);

                options.Events = new JwtBearerEvents
                {
                    OnAuthenticationFailed = async c =>
                    {
                        var logger = c.HttpContext.RequestServices.GetRequiredService <ILogger <JwtBearerHandler> >();
                        logger.LogError(c.Exception, $"Error authenticating JWTBearer token");
                        c.Response.StatusCode  = StatusCodes.Status401Unauthorized;
                        c.Response.ContentType = "text/plain"; if (environment.IsDevelopment())
                        {
                            // Debug only, in production do not share exceptions with the remote host.
                            await c.Response.WriteAsync(c.Exception.ToString());
                        }
                        await c.Response.WriteAsync("An error occurred processing yourauthentication.");
                    },

                    OnTokenValidated = async c =>
                    {
                        var claimTransformer = c.HttpContext.RequestServices.GetRequiredService <KeyCloakClaimTransformer>();
                        c.Principal          = await claimTransformer.TransformAsync(c.Principal);
                        c.Success();
                    }
                };
            })
            //cookies as default and sign in, principal will be saved as a cookie (no need to session state)
            .AddCookie(options =>
            {
                configuration.GetSection("auth:cookie").Bind(options);
                options.Cookie.SameSite = SameSiteMode.Strict;
                options.LoginPath       = "/login";
            })
            .AddOpenIdConnect(options =>     //oidc authentication for challenge authentication request
            {
                configuration.GetSection("auth:oidc").Bind(options);
                options.Events = new OpenIdConnectEvents()
                {
                    OnAuthenticationFailed = async c =>
                    {
                        var logger = c.HttpContext.RequestServices.GetRequiredService <ILogger <JwtBearerHandler> >();
                        logger.LogError(c.Exception, $"Error authenticating OIDC token");

                        c.HandleResponse();

                        c.Response.StatusCode  = StatusCodes.Status401Unauthorized;
                        c.Response.ContentType = "text/plain";
                        if (environment.IsDevelopment())
                        {
                            // Debug only, in production do not share exceptions with the remote host.
                            await c.Response.WriteAsync(c.Exception.ToString());
                        }
                        await c.Response.WriteAsync("An error occurred processing your authentication.");
                    },
                    OnTicketReceived = async c =>
                    {
                        var claimTransformer = c.HttpContext.RequestServices.GetRequiredService <KeyCloakClaimTransformer>();
                        c.Principal          = await claimTransformer.TransformAsync(c.Principal);
                        c.Success();
                    }
                };
            });

            services.AddAuthorization(options =>
            {
                //API authorization policy supports cookie or jwt authentication schemes
                options.AddPolicy("API", policy =>
                {
                    policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme);
                    policy.RequireAuthenticatedUser();
                });

                //Set API policy as default for [authorize] controllers
                options.DefaultPolicy = options.GetPolicy("API");
            });

            services.Configure <CookiePolicyOptions>(options =>
            {
                options.Secure = environment.IsDevelopment()
                    ? CookieSecurePolicy.SameAsRequest
                    : CookieSecurePolicy.Always;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            // In production, the Angular files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });

            // health checks
            services.AddHealthChecks(checks =>
            {
                checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask <IHealthCheckResult>(HealthCheckResult.Healthy("Ok")));
            });

            var keyRingPath = configuration.GetKeyRingPath();
            var dpBuilder   = services.AddDataProtection();

            if (!string.IsNullOrEmpty(keyRingPath))
            {
                log.LogInformation($"Setting data protection keys to persist in {keyRingPath}");
                dpBuilder.PersistKeysToFileSystem(new DirectoryInfo(keyRingPath));
            }
            else
            {
                log.LogWarning("data protection key folder is not set, check if KEY_RING_DIRECTORY env var is missing");
            }

            services.AddAutoMapper(typeof(Startup));
            services.AddMediatR(typeof(Startup));

            services.AddTransient <IEmailSender, EmailSender>();
            services.AddTransient <IPdfConverter, PdfConverter>();
            services.AddTransient <IReferralsService, ReferralsService>();
            services.AddTransient <IDataInterface, DataInterface>();
            // Using AddScoped rather than transient because of state. Might be incorrect.
            services.AddScoped <ICurrentUser, CurrentUserService>();
        }
예제 #17
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource rtpCts = new CancellationTokenSource(); // Cancellation token to stop the RTP stream.
            bool isCallHungup  = false;
            bool hasCallFailed = false;

            AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            Log.LogInformation($"Call destination {callUri}.");

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, 0)));

            // Un/comment this line to see/hide each SIP message sent and received.
            EnableTraceLogs(sipTransport);

            // Note this relies on the callURI host being an IP address. If it's a hostname a DNS lookup is required.
            IPAddress localIPAddress = NetServices.GetLocalAddressForRemote(callUri.ToSIPEndPoint().Address);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            var rtpSession = new RTPSession((int)SDPMediaFormatsEnum.PCMU, null, null, true, localIPAddress.AddressFamily);
            var offerSDP   = rtpSession.GetSDP(localIPAddress);

            // Create a client user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var uac = new SIPClientUserAgent(sipTransport);

            uac.CallTrying += (uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            };
            uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    rtpSession.DestinationEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);
                    Log.LogDebug($"Remote RTP socket {rtpSession.DestinationEndPoint}.");
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    await sipTransport.SendResponseAsync(okResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        rtpCts.Cancel();
                    }
                }
            };

            // Wire up the RTP receive session to the default speaker.
            var(audioOutEvent, audioOutProvider) = GetAudioOutputDevice();
            rtpSession.OnReceivedSampleReady    += (sample) =>
            {
                for (int index = 0; index < sample.Length; index++)
                {
                    short  pcm       = NAudio.Codecs.MuLawDecoder.MuLawToLinearSample(sample[index]);
                    byte[] pcmSample = new byte[] { (byte)(pcm & 0xFF), (byte)(pcm >> 8) };
                    audioOutProvider.AddSamples(pcmSample, 0, 2);
                }
            };

            // Send audio packets (in this case silence) to the callee.
            Task.Run(() => SendSilence(rtpSession, rtpCts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                null, null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                offerSDP.ToString(),
                null);

            uac.Call(callDescriptor);

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                rtpCts.Cancel();
            };

            // Give the call some time to answer.
            Task.Delay(3000).Wait();

            // Send some DTMF key presses via RTP events.
            var dtmf5 = new RTPEvent(0x05, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPSession.DTMF_EVENT_PAYLOAD_ID);

            rtpSession.SendDtmfEvent(dtmf5, rtpCts.Token).Wait();
            Task.Delay(2000, rtpCts.Token).Wait();

            var dtmf9 = new RTPEvent(0x09, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPSession.DTMF_EVENT_PAYLOAD_ID);

            rtpSession.SendDtmfEvent(dtmf9, rtpCts.Token).Wait();
            Task.Delay(2000, rtpCts.Token).Wait();

            var dtmf2 = new RTPEvent(0x02, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPSession.DTMF_EVENT_PAYLOAD_ID);

            rtpSession.SendDtmfEvent(dtmf2, rtpCts.Token).Wait();
            Task.Delay(2000, rtpCts.Token).ContinueWith((task) => { }).Wait(); // Don't care about the exception if the cancellation token is set.

            Log.LogInformation("Exiting...");

            rtpCts.Cancel();
            audioOutEvent?.Stop();
            rtpSession.CloseSession(null);

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
예제 #18
0
 public void Warning(string message)
 {
     _readLogger.LogWarning(message);
 }
예제 #19
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            ManualResetEvent exitMre       = new ManualResetEvent(false);
            bool             isCallHungup  = false;
            bool             hasCallFailed = false;

            Log = AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            if (args != null && args.Length > 0)
            {
                if (!SIPURI.TryParse(args[0], out callUri))
                {
                    Log.LogWarning($"Command line argument could not be parsed as a SIP URI {args[0]}");
                }
            }
            Log.LogInformation($"Call destination {callUri}.");

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            EnableTraceLogs(sipTransport);

            var audioSession = new WindowsAudioEndPoint(new AudioEncoder());
            var rtpSession   = new VoIPMediaSession(audioSession.ToMediaEndPoints());

            var offerSDP = rtpSession.CreateOffer(null);

            // Create a client user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var uac = new SIPClientUserAgent(sipTransport);

            uac.CallTrying  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallRinging += async(uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
                if (resp.Status == SIPResponseStatusCodesEnum.SessionProgress)
                {
                    await rtpSession.Start();
                }
            };
            uac.CallFailed += (uac, err, resp) =>
            {
                Log.LogWarning($"Call attempt to {uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += async(iuac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    var result = rtpSession.SetRemoteDescription(SdpType.answer, SDP.ParseSDPDescription(resp.Body));
                    if (result == SetDescriptionResultEnum.OK)
                    {
                        await rtpSession.Start();
                    }
                    else
                    {
                        Log.LogWarning($"Failed to set remote description {result}.");
                        uac.Hangup();
                    }
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    await sipTransport.SendResponseAsync(okResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        exitMre.Set();
                    }
                }
            };

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                callUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                offerSDP.ToString(),
                null);

            uac.Call(callDescriptor, null);
            uac.ServerTransaction.TransactionTraceMessage += (tx, msg) => Log.LogInformation($"UAC tx trace message. {msg}");

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitMre.Set();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitMre.WaitOne();

            Log.LogInformation("Exiting...");

            rtpSession.Close(null);

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
예제 #20
0
        static async Task Main(string[] args)
        {
            Console.WriteLine("SIPSorcery Video Phone Command Line Demo");
            Console.WriteLine("Press ctrl-c to exit.");

            Log = AddConsoleLogger();
            ManualResetEvent exitMRE        = new ManualResetEvent(false);
            ManualResetEvent waitForCallMre = new ManualResetEvent(false);

            var parseResult = Parser.Default.ParseArguments <Options>(args);

            _options = (parseResult as Parsed <Options>)?.Value;

            if (parseResult.Tag != ParserResultType.NotParsed)
            {
                if (_options.ListCameras)
                {
                    #region List webcams.

                    var webcams = await WindowsVideoEndPoint.GetVideoCatpureDevices();

                    if (webcams == null || webcams.Count == 0)
                    {
                        Console.WriteLine("No webcams were found.");
                    }
                    else
                    {
                        var index = 0;
                        foreach (var webcam in webcams)
                        {
                            Console.WriteLine($"{index}: \"{webcam.Name}\", use --cam={index}.");
                            index++;
                        }
                    }

                    #endregion
                }
                else if (_options.ListFormats != null)
                {
                    #region List webcam formats.

                    var webcams = await WindowsVideoEndPoint.GetVideoCatpureDevices();

                    if (webcams == null || webcams.Count == 0)
                    {
                        Console.WriteLine("No webcams were found.");
                    }
                    else if (_options.ListFormats >= webcams.Count)
                    {
                        Console.WriteLine($"No webcam available for index {_options.ListFormats}.");
                    }
                    else
                    {
                        string webcamName = webcams[_options.ListFormats.Value].Name;
                        var    formats    = await WindowsVideoEndPoint.GetDeviceFrameFormats(webcamName);

                        Console.WriteLine($"Video frame formats for {webcamName}.");
                        foreach (var vidFmt in formats)
                        {
                            float  vidFps = vidFmt.MediaFrameFormat.FrameRate.Numerator / vidFmt.MediaFrameFormat.FrameRate.Denominator;
                            string pixFmt = vidFmt.MediaFrameFormat.Subtype == WindowsVideoEndPoint.MF_I420_PIXEL_FORMAT ? "I420" : vidFmt.MediaFrameFormat.Subtype;
                            Console.WriteLine($"{vidFmt.Width}x{vidFmt.Height} {vidFps:0.##}fps {pixFmt}");
                        }
                    }

                    #endregion
                }
                else
                {
                    string webcamName = null;

                    if (_options.WebcamIndex != null)
                    {
                        var webcams = await WindowsVideoEndPoint.GetVideoCatpureDevices();

                        if (webcams == null || webcams.Count == 0)
                        {
                            Console.WriteLine("No webcams were found.");
                            Application.Exit();
                        }
                        else if (webcams.Count < _options.WebcamIndex)
                        {
                            Console.WriteLine($"No webcam available for index {_options.WebcamIndex}.");
                            Application.Exit();
                        }
                        else
                        {
                            webcamName = webcams[_options.WebcamIndex.Value].Name;
                            Console.WriteLine($"Using webcam {webcamName}.");
                        }
                    }

                    _sipTransport = new SIPTransport();

                    if (string.IsNullOrEmpty(_options.CallDestination))
                    {
                        // We haven't been asked to place a call so we're listening.
                        IPAddress listenAddress  = (System.Net.Sockets.Socket.OSSupportsIPv6) ? IPAddress.IPv6Any : IPAddress.Any;
                        var       listenEndPoint = new IPEndPoint(listenAddress, SIP_PORT_DEFAULT);

                        try
                        {
                            SIPUDPChannel udpChannel = new SIPUDPChannel(listenEndPoint, true);
                            _sipTransport.AddSIPChannel(udpChannel);
                        }
                        catch (ApplicationException appExcp)
                        {
                            Console.WriteLine($"Failed to create UDP SIP channel on {listenEndPoint}, error {appExcp.Message}.");
                            SIPUDPChannel udpChannel = new SIPUDPChannel(new IPEndPoint(listenAddress, 0), true);
                            _sipTransport.AddSIPChannel(udpChannel);
                        }

                        var listeningEP = _sipTransport.GetSIPChannels().First().ListeningSIPEndPoint;
                        Console.WriteLine($"Listening for incoming call on {listeningEP}.");
                    }

                    EnableTraceLogs(_sipTransport);

                    // Open a window to display the video feed from the remote SIP party.
                    _form          = new Form();
                    _form.Text     = string.IsNullOrEmpty(_options.CallDestination) ? "Listener" : "Caller";
                    _form.AutoSize = true;
                    _form.BackgroundImageLayout = ImageLayout.Center;
                    _localVideoPicBox           = new PictureBox
                    {
                        Size     = new Size(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT),
                        Location = new Point(0, 0),
                        Visible  = true
                    };
                    _remoteVideoPicBox = new PictureBox
                    {
                        Size     = new Size(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT),
                        Location = new Point(0, VIDEO_FRAME_HEIGHT),
                        Visible  = true
                    };
                    _form.Controls.Add(_localVideoPicBox);
                    _form.Controls.Add(_remoteVideoPicBox);

                    var userAgent = new SIPUserAgent(_sipTransport, null, true);
                    userAgent.OnCallHungup += (dialog) => exitMRE.Set();

                    WindowsAudioEndPoint windowsAudioEndPoint = null;
                    if (!_options.NoAudio)
                    {
                        windowsAudioEndPoint = new WindowsAudioEndPoint(new AudioEncoder());
                        windowsAudioEndPoint.RestrictFormats(x => x.Codec == AudioCodecsEnum.G722);
                    }

                    MediaEndPoints mediaEndPoints = null;

                    if (_options.TestPattern && _options.WebcamIndex == null)
                    {
                        var testPattern = new VideoTestPatternSource(new FFmpegVideoEncoder());
                        var decoderSink = new DecoderVideoSink(new FFmpegVideoEncoder());
                        //var decoderSink = new DecoderVideoSink(new VpxVideoEncoder());

                        testPattern.RestrictFormats(format => format.Codec == VIDEO_CODEC);
                        decoderSink.RestrictFormats(format => format.Codec == VIDEO_CODEC);

                        mediaEndPoints = new MediaEndPoints
                        {
                            AudioSink   = windowsAudioEndPoint,
                            AudioSource = windowsAudioEndPoint,
                            VideoSink   = decoderSink,
                            VideoSource = testPattern,
                        };
                    }
                    else
                    {
                        WindowsVideoEndPoint windowsVideoEndPoint = webcamName switch
                        {
                            null => new WindowsVideoEndPoint(new FFmpegVideoEncoder()),
                            _ => new WindowsVideoEndPoint(new FFmpegVideoEncoder(), webcamName),
                        };
                        windowsVideoEndPoint.RestrictFormats(format => format.Codec == VIDEO_CODEC);

                        mediaEndPoints = new MediaEndPoints
                        {
                            AudioSink   = windowsAudioEndPoint,
                            AudioSource = windowsAudioEndPoint,
                            VideoSink   = windowsVideoEndPoint,
                            VideoSource = windowsVideoEndPoint,
                        };
                    }

                    mediaEndPoints.VideoSource.OnVideoSourceRawSample += (uint durationMilliseconds, int width, int height, byte[] sample, VideoPixelFormatsEnum pixelFormat) =>
                    {
                        if (_isFormActivated)
                        {
                            _form?.BeginInvoke(new Action(() =>
                            {
                                if (_form.Handle != IntPtr.Zero)
                                {
                                    int stride = width * 3;
                                    if (pixelFormat == VideoPixelFormatsEnum.I420)
                                    {
                                        sample = PixelConverter.I420toBGR(sample, width, height, out stride);
                                    }

                                    if (_localVideoPicBox.Width != width || _localVideoPicBox.Height != height)
                                    {
                                        Log.LogDebug($"Adjusting local video display from {_localVideoPicBox.Width}x{_localVideoPicBox.Height} to {width}x{height}.");
                                        _localVideoPicBox.Width  = width;
                                        _localVideoPicBox.Height = height;
                                    }

                                    unsafe
                                    {
                                        fixed(byte *s = sample)
                                        {
                                            System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)s);
                                            _localVideoPicBox.Image        = bmpImage;
                                        }
                                    }
                                }
                            }));
                        }
                    };

                    Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
                    {
                        e.Cancel = true;
                        Log.LogInformation("Exiting...");
                        waitForCallMre.Set();
                        exitMRE.Set();
                    };

                    if (string.IsNullOrEmpty(_options.CallDestination))
                    {
                        ActivateForm();

                        userAgent.OnIncomingCall += async(ua, req) =>
                        {
                            var voipMediaSession = new VoIPMediaSession(mediaEndPoints);
                            voipMediaSession.AcceptRtpFromAny = true;
                            if (voipMediaSession.VideoLocalTrack != null)
                            {
                                voipMediaSession.VideoLocalTrack.MaximumBandwidth = MAXIMUM_VIDEO_BANDWIDTH;
                            }

                            var uas = userAgent.AcceptCall(req);
                            await userAgent.Answer(uas, voipMediaSession);

                            Console.WriteLine("Starting local video source...");
                            await mediaEndPoints.VideoSource.StartVideo().ConfigureAwait(false);

                            waitForCallMre.Set();
                        };

                        Console.WriteLine("Waiting for incoming call...");
                        waitForCallMre.WaitOne();
                    }
                    else
                    {
                        var voipMediaSession = new VoIPMediaSession(mediaEndPoints);
                        voipMediaSession.AcceptRtpFromAny = true;
                        if (voipMediaSession.VideoLocalTrack != null)
                        {
                            voipMediaSession.VideoLocalTrack.MaximumBandwidth = MAXIMUM_VIDEO_BANDWIDTH;
                        }

                        ActivateForm();

                        Console.WriteLine("Starting local video source...");
                        await mediaEndPoints.VideoSource.StartVideo().ConfigureAwait(false);

                        // Place the call and wait for the result.
                        Task <bool> callTask = userAgent.Call(_options.CallDestination, null, null, voipMediaSession);
                        callTask.Wait(CALL_TIMEOUT_SECONDS * 1000);
                    }

                    if (userAgent.IsCallActive)
                    {
                        Log.LogInformation("Call attempt successful.");
                        mediaEndPoints.VideoSink.OnVideoSinkDecodedSample += (byte[] bmp, uint width, uint height, int stride, VideoPixelFormatsEnum pixelFormat) =>
                        {
                            if (_isFormActivated)
                            {
                                _form?.BeginInvoke(new Action(() =>
                                {
                                    if (_form.Handle != IntPtr.Zero)
                                    {
                                        unsafe
                                        {
                                            if (_remoteVideoPicBox.Width != (int)width || _remoteVideoPicBox.Height != (int)height)
                                            {
                                                Log.LogDebug($"Adjusting remote video display from {_remoteVideoPicBox.Width}x{_remoteVideoPicBox.Height} to {width}x{height}.");
                                                _remoteVideoPicBox.Width  = (int)width;
                                                _remoteVideoPicBox.Height = (int)height;
                                            }

                                            fixed(byte *s = bmp)
                                            {
                                                System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap((int)width, (int)height, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)s);
                                                _remoteVideoPicBox.Image       = bmpImage;
                                            }
                                        }
                                    }
                                }));
                            }
                        };
                    }
                    else
                    {
                        Log.LogWarning("Call attempt failed.");
                        Console.WriteLine("Press ctrl-c to exit.");
                    }

                    exitMRE.WaitOne();

                    if (userAgent.IsCallActive)
                    {
                        Log.LogInformation("Hanging up.");
                        userAgent.Hangup();
                    }

                    Task.Delay(1000).Wait();

                    // Clean up.
                    if (_form.Handle != IntPtr.Zero)
                    {
                        _form.BeginInvoke(new Action(() => _form.Close()));
                    }
                    _sipTransport.Shutdown();
                }
            }
        }
예제 #21
0
 public void LogWarning(string message)
 {
     _logger.LogWarning(message);
 }
예제 #22
0
파일: Program.cs 프로젝트: tilosp/jellyfin
        private static async Task StartApp(StartupOptions options)
        {
            ServerApplicationPaths appPaths = CreateApplicationPaths(options);

            // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager
            Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath);

            IConfiguration appConfig = await CreateConfiguration(appPaths).ConfigureAwait(false);

            CreateLogger(appConfig, appPaths);

            _logger = _loggerFactory.CreateLogger("Main");

            AppDomain.CurrentDomain.UnhandledException += (sender, e)
                                                          => _logger.LogCritical((Exception)e.ExceptionObject, "Unhandled Exception");

            // Intercept Ctrl+C and Ctrl+Break
            Console.CancelKeyPress += (sender, e) =>
            {
                if (_tokenSource.IsCancellationRequested)
                {
                    return; // Already shutting down
                }

                e.Cancel = true;
                _logger.LogInformation("Ctrl+C, shutting down");
                Environment.ExitCode = 128 + 2;
                Shutdown();
            };

            // Register a SIGTERM handler
            AppDomain.CurrentDomain.ProcessExit += (sender, e) =>
            {
                if (_tokenSource.IsCancellationRequested)
                {
                    return; // Already shutting down
                }

                _logger.LogInformation("Received a SIGTERM signal, shutting down");
                Environment.ExitCode = 128 + 15;
                Shutdown();
            };

            _logger.LogInformation("Jellyfin version: {Version}", Assembly.GetEntryAssembly().GetName().Version);

            ApplicationHost.LogEnvironmentInfo(_logger, appPaths);

            // Increase the max http request limit
            // The default connection limit is 10 for ASP.NET hosted applications and 2 for all others.
            ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);

            // Disable the "Expect: 100-Continue" header by default
            // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
            ServicePointManager.Expect100Continue = false;

// CA5359: Do Not Disable Certificate Validation
#pragma warning disable CA5359

            // Allow all https requests
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return(true); });
#pragma warning restore CA5359

            Batteries_V2.Init();
            if (raw.sqlite3_enable_shared_cache(1) != raw.SQLITE_OK)
            {
                _logger.LogWarning("Failed to enable shared cache for SQLite");
            }

            using (var appHost = new CoreAppHost(
                       appPaths,
                       _loggerFactory,
                       options,
                       new ManagedFileSystem(_loggerFactory.CreateLogger <ManagedFileSystem>(), appPaths),
                       new NullImageEncoder(),
                       new NetworkManager(_loggerFactory.CreateLogger <NetworkManager>()),
                       appConfig))
            {
                await appHost.InitAsync(new ServiceCollection()).ConfigureAwait(false);

                appHost.ImageProcessor.ImageEncoder = GetImageEncoder(appPaths, appHost.LocalizationManager);

                await appHost.RunStartupTasksAsync().ConfigureAwait(false);

                try
                {
                    // Block main thread until shutdown
                    await Task.Delay(-1, _tokenSource.Token).ConfigureAwait(false);
                }
                catch (TaskCanceledException)
                {
                    // Don't throw on cancellation
                }
            }

            if (_restartOnShutdown)
            {
                StartNewInstance(options);
            }
        }
예제 #23
0
        private static RTCPeerConnection Createpc(WebSocketContext context)
        {
            List <RTCCertificate> presetCertificates = null;

            if (File.Exists(LOCALHOST_CERTIFICATE_PATH))
            {
                var localhostCert = new X509Certificate2(LOCALHOST_CERTIFICATE_PATH, (string)null, X509KeyStorageFlags.Exportable);
                presetCertificates = new List <RTCCertificate> {
                    new RTCCertificate {
                        Certificate = localhostCert
                    }
                };
            }

            RTCConfiguration pcConfiguration = new RTCConfiguration
            {
                certificates = presetCertificates,
                X_RemoteSignallingAddress = context.UserEndPoint.Address,
                iceServers = new List <RTCIceServer> {
                    new RTCIceServer
                    {
                        urls           = SIPSORCERY_STUN_SERVER,
                        username       = SIPSORCERY_STUN_SERVER_USERNAME,
                        credential     = SIPSORCERY_STUN_SERVER_PASSWORD,
                        credentialType = RTCIceCredentialType.password
                    }
                },
                iceTransportPolicy = RTCIceTransportPolicy.all
            };

            var pc = new RTCPeerConnection(pcConfiguration);

            // Add inactive audio and video tracks.
            MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> {
                new SDPMediaFormat(SDPMediaFormatsEnum.PCMU)
            }, MediaStreamStatusEnum.RecvOnly);

            pc.addTrack(audioTrack);
            MediaStreamTrack videoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPMediaFormat> {
                new SDPMediaFormat(SDPMediaFormatsEnum.VP8)
            }, MediaStreamStatusEnum.Inactive);

            pc.addTrack(videoTrack);

            pc.onicecandidateerror     += (candidate, error) => logger.LogWarning($"Error adding remote ICE candidate. {error} {candidate}");
            pc.onconnectionstatechange += (state) => logger.LogDebug($"Peer connection state changed to {state}.");
            pc.OnReceiveReport         += (type, rtcp) => logger.LogDebug($"RTCP {type} report received.");
            pc.OnRtcpBye += (reason) => logger.LogDebug($"RTCP BYE receive, reason: {(string.IsNullOrWhiteSpace(reason) ? "<none>" : reason)}.");

            pc.onicecandidate += (candidate) =>
            {
                if (pc.signalingState == RTCSignalingState.have_local_offer ||
                    pc.signalingState == RTCSignalingState.have_remote_offer)
                {
                    context.WebSocket.Send($"candidate:{candidate}");
                }
            };

            // Peer ICE connection state changes are for ICE events such as the STUN checks completing.
            pc.oniceconnectionstatechange += (state) =>
            {
                logger.LogDebug($"ICE connection state change to {state}.");
            };

            return(pc);
        }
예제 #24
0
        private static async Task ProcessEmail(IAsyncCollector <SendGridMessage> emailProvider, ILogger log,
                                               BaseEmail topicMessage, CancellationToken token)
        {
            var message         = new SendGridMessage();
            var personalization = new Personalization();


            if (topicMessage.TemplateId != null)
            {
                message.Asm = new ASM
                {
                    GroupId = topicMessage.UnsubscribeGroup
                };
                message.TemplateId = topicMessage.TemplateId;
                message.Subject    = topicMessage.Subject;
                if (topicMessage.Campaign != null)
                {
                    message.AddCategory(topicMessage.Campaign);
                    message.TrackingSettings = new TrackingSettings
                    {
                        Ganalytics = new Ganalytics
                        {
                            UtmCampaign = topicMessage.Campaign,
                            UtmSource   = "SendGrid",
                            UtmMedium   = "Email",
                            Enable      = true
                        }
                    };
                    message.TrackingSettings.Ganalytics.Enable = true;
                }

                personalization.Substitutions = new Dictionary <string, string>();
                foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(topicMessage))
                {
                    var p = prop.GetValue(topicMessage);
                    personalization.Substitutions[$"-{prop.Name}-"] = p?.ToString() ?? string.Empty;
                    //personalization.AddSubstitution($"-{prop.Name}-", p?.ToString() ?? string.Empty);
                }
                message.Personalizations = new List <Personalization>()
                {
                    personalization
                };
            }
            else
            {
                message.AddContent("text/html", topicMessage.ToString());
                message.Subject = topicMessage.Subject;
                if (topicMessage.Bcc != null)
                {
                    foreach (var bcc in topicMessage.Bcc)
                    {
                        message.AddBcc(bcc);
                    }
                }
                log.LogWarning("error with template name" + topicMessage.TemplateId);
            }

            CultureInfo.DefaultThreadCurrentCulture = topicMessage.Info;
            message.AddFromResource(topicMessage.Info);
            message.AddTo(topicMessage.To);

            await emailProvider.AddAsync(message, token);
        }
예제 #25
0
        /// <summary>
        /// Runs a single task as part of the overall job.
        /// </summary>
        /// <param name="options">The options that dictate the type of task to run.</param>
        /// <param name="taskNumber">The number assigned to this task.</param>
        /// <returns>A boolean indicating whether this single task succeeded or not.</returns>
        private static async Task <bool> RunTask(Options options, int taskNumber)
        {
            SIPTransport sipTransport = new SIPTransport();

            try
            {
                DateTime startTime = DateTime.Now;

                (var dstEp, var dstUri) = ParseDestination(options.Destination);

                logger.LogDebug($"Destination IP end point {dstEp} and SIP URI {dstUri}");

                //IPAddress localAddress = (dstEp.Address.AddressFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Any : IPAddress.Any;
                //SIPChannel sipChannel = null;

                //switch (dstEp.Protocol)
                //{
                //    case SIPProtocolsEnum.tcp:
                //        sipChannel = new SIPTCPChannel(new IPEndPoint(localAddress, DEFAULT_SIP_CLIENT_PORT));
                //        (sipChannel as SIPTCPChannel).DisableLocalTCPSocketsCheck = true; // Allow sends to listeners on this host.
                //        break;
                //    case SIPProtocolsEnum.tls:
                //        var certificate = new X509Certificate2(@"localhost.pfx", "");
                //        sipChannel = new SIPTLSChannel(certificate, new IPEndPoint(localAddress, DEFAULT_SIPS_CLIENT_PORT));
                //        break;
                //    case SIPProtocolsEnum.udp:
                //        sipChannel = new SIPUDPChannel(new IPEndPoint(localAddress, DEFAULT_SIP_CLIENT_PORT));
                //        break;
                //    case SIPProtocolsEnum.ws:
                //        sipChannel = new SIPClientWebSocketChannel();
                //        break;
                //    case SIPProtocolsEnum.wss:
                //        sipChannel = new SIPClientWebSocketChannel();
                //        break;
                //    default:
                //        throw new ApplicationException($"Don't know how to create SIP channel for transport {dstEp.Protocol}.");
                //}

                //sipTransport.AddSIPChannel(sipChannel);

                Task <bool> task = null;

                switch (options.Scenario)
                {
                case Scenarios.uac:
                    task = InitiateCallTaskAsync(sipTransport, dstUri);
                    break;

                case Scenarios.opt:
                default:
                    task = SendOptionsTaskAsync(sipTransport, dstUri);
                    break;
                }

                var result = await Task.WhenAny(task, Task.Delay(options.Timeout * 1000));

                TimeSpan duration = DateTime.Now.Subtract(startTime);
                bool     failed   = false;

                if (!task.IsCompleted)
                {
                    logger.LogWarning($"=> Request to {dstEp} did not get a response on task {taskNumber} after {duration.TotalMilliseconds.ToString("0")}ms.");
                    failed = true;
                }
                else if (!task.Result)
                {
                    logger.LogWarning($"=> Request to {dstEp} did not get the expected response on task {taskNumber} after {duration.TotalMilliseconds.ToString("0")}ms.");
                    failed = true;
                }
                else
                {
                    logger.LogInformation($"=> Got correct response on send {taskNumber} in {duration.TotalMilliseconds.ToString("0")}ms.");
                }

                return(!failed);
            }
            finally
            {
                logger.LogDebug("Shutting down the SIP transport...");
                sipTransport.Shutdown();
            }
        }
예제 #26
0
        public static async Task <int> MainAsync(IConfigurationRoot configuration)
        {
            string logLevel = configuration.GetValue($"{Logger.RuntimeLogLevelEnvKey}", "info");

            Logger.SetLogLevel(logLevel);

            // Set the LoggerFactory used by the Routing code.
            if (configuration.GetValue("EnableRoutingLogging", false))
            {
                Routing.Core.Routing.LoggerFactory = Logger.Factory;
            }

            X509Certificate2 cert;
            IEnumerable <X509Certificate2> chain;
            string edgeHubConnectionString = configuration.GetValue <string>(Constants.IotHubConnectionStringVariableName);

            // When connection string is not set it is edged mode
            if (string.IsNullOrEmpty(edgeHubConnectionString))
            {
                var      workloadUri     = new Uri(configuration.GetValue <string>(Constants.WorkloadUriVariableName));
                string   edgeHubHostname = configuration.GetValue <string>(Constants.EdgeDeviceHostnameVariableName);
                string   moduleId        = configuration.GetValue <string>(Constants.ModuleIdVariableName);
                string   generationId    = configuration.GetValue <string>(Constants.ModuleGenerationIdVariableName);
                DateTime expiration      = DateTime.UtcNow.AddDays(Constants.CertificateValidityDays);
                (cert, chain) = await CertificateHelper.GetServerCertificatesFromEdgelet(workloadUri, Constants.WorkloadApiVersion, moduleId, generationId, edgeHubHostname, expiration);
            }
            else
            {
                string edgeHubCertPath = configuration.GetValue <string>(Constants.EdgeHubServerCertificateFileKey);
                cert = new X509Certificate2(edgeHubCertPath);
                string edgeHubCaChainCertPath = configuration.GetValue <string>(Constants.EdgeHubServerCAChainCertificateFileKey);
                chain = CertificateHelper.GetServerCACertificatesFromFile(edgeHubCaChainCertPath);
            }

            // TODO: set certificate for Startup without the cache
            ServerCertificateCache.X509Certificate = cert;

            int     port    = configuration.GetValue("httpSettings:port", 443);
            Hosting hosting = Hosting.Initialize(port);

            IContainer container = hosting.Container;

            ILogger logger = container.Resolve <ILoggerFactory>().CreateLogger("EdgeHub");

            logger.LogInformation("Starting Edge Hub");
            VersionInfo versionInfo = VersionInfo.Get(Constants.VersionInfoFileName);

            if (versionInfo != VersionInfo.Empty)
            {
                logger.LogInformation($"Version - {versionInfo.ToString(true)}");
            }
            LogLogo(logger);

            if (chain != null)
            {
                logger.LogInformation("Installing intermediate certificates.");

                CertificateHelper.InstallCerts(
                    RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? StoreName.CertificateAuthority : StoreName.Root,
                    StoreLocation.CurrentUser,
                    chain);
            }
            else
            {
                logger.LogWarning("Unable to find intermediate certificates.");
            }

            // EdgeHub and CloudConnectionProvider have a circular dependency. So need to Bind the EdgeHub to the CloudConnectionProvider.
            IEdgeHub edgeHub = await container.Resolve <Task <IEdgeHub> >();

            var cloudConnectionProvider = container.Resolve <ICloudConnectionProvider>();

            cloudConnectionProvider.BindEdgeHub(edgeHub);

            // EdgeHub cloud proxy and DeviceConnectivityManager have a circular dependency,
            // so the cloud proxy has to be set on the DeviceConnectivityManager after both have been initialized.
            var         deviceConnectivityManager = container.Resolve <IDeviceConnectivityManager>();
            ICloudProxy cloudProxy = await container.ResolveNamed <Task <ICloudProxy> >("EdgeHubCloudProxy");

            (deviceConnectivityManager as DeviceConnectivityManager)?.SetTestCloudProxy(cloudProxy);

            logger.LogInformation("Initializing configuration");
            IConfigSource configSource = await container.Resolve <Task <IConfigSource> >();

            ConfigUpdater configUpdater = await container.Resolve <Task <ConfigUpdater> >();

            await configUpdater.Init(configSource);

            (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler)
                = ShutdownHandler.Init(ShutdownWaitPeriod, logger);

            var protocolHeads = new List <IProtocolHead>();

            if (configuration.GetValue("mqttSettings:enabled", true))
            {
                protocolHeads.Add(await container.Resolve <Task <MqttProtocolHead> >());
            }

            if (configuration.GetValue("amqpSettings:enabled", true))
            {
                protocolHeads.Add(await container.Resolve <Task <AmqpProtocolHead> >());
            }

            if (configuration.GetValue("httpSettings:enabled", true))
            {
                protocolHeads.Add(new HttpProtocolHead(hosting.WebHost));
            }

            using (IProtocolHead protocolHead = new EdgeHubProtocolHead(protocolHeads, logger))
            {
                await protocolHead.StartAsync();

                await cts.Token.WhenCanceled();

                await Task.WhenAny(protocolHead.CloseAsync(CancellationToken.None), Task.Delay(TimeSpan.FromSeconds(10), CancellationToken.None));
            }

            completed.Set();
            handler.ForEach(h => GC.KeepAlive(h));
            return(0);
        }
예제 #27
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery Call Hold and Blind Transfer example.");
            Console.WriteLine("Press 'c' to initiate a call to the default destination.");
            Console.WriteLine("Press 'h' to place an established call on and off hold.");
            Console.WriteLine("Press 'H' to hangup an established call.");
            Console.WriteLine("Press 't' to request a blind transfer on an established call.");
            Console.WriteLine("Press 'q' or ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            Log = AddConsoleLogger();

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            Console.WriteLine($"Listening for incoming calls on: {sipTransport.GetSIPChannels().First().ListeningEndPoint}.");

            EnableTraceLogs(sipTransport);

            var winAudio = new WindowsAudioEndPoint(new AudioEncoder());

            winAudio.RestrictCodecs(new List <AudioCodecsEnum> {
                AudioCodecsEnum.PCMU
            });

            // Create a client/server user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var userAgent = new SIPUserAgent(sipTransport, null, true);

            userAgent.RemotePutOnHold   += () => Log.LogInformation("Remote call party has placed us on hold.");
            userAgent.RemoteTookOffHold += () => Log.LogInformation("Remote call party took us off hold.");
            userAgent.OnIncomingCall    += async(ua, req) =>
            {
                Log.LogInformation($"Incoming call from {req.Header.From.FriendlyDescription()} at {req.RemoteSIPEndPoint}.");
                var uas = userAgent.AcceptCall(req);

                if (userAgent?.IsCallActive == true)
                {
                    // If we are already on a call return a busy response.
                    Log.LogWarning($"Busy response returned for incoming call request.");
                    uas.Reject(SIPResponseStatusCodesEnum.BusyHere, null);
                }
                else
                {
                    var voipSession = new VoIPMediaSession(winAudio.ToMediaEndPoints());
                    voipSession.AcceptRtpFromAny = true;
                    var answerResult = await userAgent.Answer(uas, voipSession);
                }
            };

            // At this point the call has been initiated and everything will be handled in an event handler.
            Task.Run(async() =>
            {
                try
                {
                    while (!exitCts.Token.WaitHandle.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();

                        if (keyProps.KeyChar == 'c')
                        {
                            if (!userAgent.IsCallActive)
                            {
                                var voipSession = new VoIPMediaSession(winAudio.ToMediaEndPoints());
                                voipSession.AcceptRtpFromAny = true;
                                bool callResult = await userAgent.Call(DEFAULT_DESTINATION_SIP_URI, SIP_USERNAME, SIP_PASSWORD, voipSession);

                                Log.LogInformation($"Call attempt {((callResult) ? "successfull" : "failed")}.");
                            }
                            else
                            {
                                Log.LogWarning("There is already an active call.");
                            }
                        }
                        else if (keyProps.KeyChar == 'h')
                        {
                            // Place call on/off hold.
                            if (userAgent.IsCallActive)
                            {
                                if (userAgent.IsOnLocalHold)
                                {
                                    Log.LogInformation("Taking the remote call party off hold.");
                                    (userAgent.MediaSession as VoIPMediaSession).TakeOffHold();
                                    userAgent.TakeOffHold();
                                }
                                else
                                {
                                    Log.LogInformation("Placing the remote call party on hold.");
                                    await(userAgent.MediaSession as VoIPMediaSession).PutOnHold();
                                    userAgent.PutOnHold();
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to put on hold.");
                            }
                        }
                        else if (keyProps.KeyChar == 'H')
                        {
                            if (userAgent.IsCallActive)
                            {
                                Log.LogInformation("Hanging up call.");
                                userAgent.Hangup();
                            }
                        }
                        else if (keyProps.KeyChar == 't')
                        {
                            // Initiate a blind transfer to the remote call party.
                            if (userAgent.IsCallActive)
                            {
                                var transferURI = SIPURI.ParseSIPURI(TRANSFER_DESTINATION_SIP_URI);
                                bool result     = await userAgent.BlindTransfer(transferURI, TimeSpan.FromSeconds(TRANSFER_TIMEOUT_SECONDS), exitCts.Token);
                                if (result)
                                {
                                    // If the transfer was accepted the original call will already have been hungup.
                                    // Wait a second for the transfer NOTIFY request to arrive.
                                    await Task.Delay(1000);
                                    exitCts.Cancel();
                                }
                                else
                                {
                                    Log.LogWarning($"Transfer to {TRANSFER_DESTINATION_SIP_URI} failed.");
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to transfer.");
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    Log.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            if (userAgent != null)
            {
                if (userAgent.IsCallActive)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }

            #endregion
        }
예제 #28
0
 public void LogWarning(string data)
 {
     _baseLogger.LogWarning(data);
 }
예제 #29
0
        //private delegate void MediaSampleReadyDelegate(SDPMediaTypesEnum mediaType, uint duration, byte[] sample);
        //private static event MediaSampleReadyDelegate OnMediaFromSIPSampleReady;

        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery SIP to WebRTC example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            Log = AddConsoleLogger();

            // Start web socket.
            Console.WriteLine("Starting web socket server...");
            _webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT, true);
            _webSocketServer.SslConfiguration.ServerCertificate          = new X509Certificate2(WEBSOCKET_CERTIFICATE_PATH);
            _webSocketServer.SslConfiguration.CheckCertificateRevocation = false;
            //_webSocketServer.Log.Level = WebSocketSharp.LogLevel.Debug;
            _webSocketServer.AddWebSocketService <SDPExchange>("/", (sdpExchanger) =>
            {
                sdpExchanger.WebSocketOpened   += SendSDPOffer;
                sdpExchanger.SDPAnswerReceived += SDPAnswerReceived;
            });
            _webSocketServer.Start();

            Console.WriteLine($"Waiting for browser web socket connection to {_webSocketServer.Address}:{_webSocketServer.Port}...");

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            //EnableTraceLogs(sipTransport);

            RTPSession rtpSession = null;

            // Create a SIP user agent to receive a call from a remote SIP client.
            // Wire up event handlers for the different stages of the call.
            var userAgent = new SIPUserAgent(sipTransport, null);

            // We're only answering SIP calls, not placing them.
            userAgent.OnCallHungup += (dialog) =>
            {
                Log.LogInformation($"Call hungup by remote party.");
                exitCts.Cancel();
            };
            userAgent.ServerCallCancelled += (uas) => Log.LogInformation("Incoming call cancelled by caller.");

            sipTransport.SIPTransportRequestReceived += async(localEndPoint, remoteEndPoint, sipRequest) =>
            {
                if (sipRequest.Header.From != null &&
                    sipRequest.Header.From.FromTag != null &&
                    sipRequest.Header.To != null &&
                    sipRequest.Header.To.ToTag != null)
                {
                    // This is an in-dialog request that will be handled directly by a user agent instance.
                }
                else if (sipRequest.Method == SIPMethodsEnum.INVITE)
                {
                    if (userAgent?.IsCallActive == true)
                    {
                        Log.LogWarning($"Busy response returned for incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        // If we are already on a call return a busy response.
                        UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                        SIPResponse          busyResponse   = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BusyHere, null);
                        uasTransaction.SendFinalResponse(busyResponse);
                    }
                    else
                    {
                        Log.LogInformation($"Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        var incomingCall = userAgent.AcceptCall(sipRequest);

                        rtpSession = new RTPSession(false, false, false);
                        rtpSession.AcceptRtpFromAny = true;
                        MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> {
                            new SDPMediaFormat(SDPMediaFormatsEnum.PCMU)
                        });
                        rtpSession.addTrack(audioTrack);

                        await userAgent.Answer(incomingCall, rtpSession);

                        rtpSession.OnRtpPacketReceived += (ep, mediaType, rtpPacket) => ForwardMedia(mediaType, rtpPacket);

                        Log.LogInformation($"Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}.");
                    }
                }
                else
                {
                    Log.LogDebug($"SIP {sipRequest.Method} request received but no processing has been set up for it, rejecting.");
                    SIPResponse notAllowedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                    await sipTransport.SendResponseAsync(notAllowedResponse);
                }
            };

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            rtpSession?.Close("app exit");

            if (userAgent != null)
            {
                if (userAgent.IsCallActive)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }

            #endregion
        }
예제 #30
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery user agent server example.");
            Console.WriteLine("Press h to hangup a call or ctrl-c to exit.");

            EnableConsoleLogger();

            IPAddress listenAddress     = IPAddress.Any;
            IPAddress listenIPv6Address = IPAddress.IPv6Any;

            if (args != null && args.Length > 0)
            {
                if (!IPAddress.TryParse(args[0], out var customListenAddress))
                {
                    Log.LogWarning($"Command line argument could not be parsed as an IP address \"{args[0]}\"");
                    listenAddress = IPAddress.Any;
                }
                else
                {
                    if (customListenAddress.AddressFamily == AddressFamily.InterNetwork)
                    {
                        listenAddress = customListenAddress;
                    }
                    if (customListenAddress.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        listenIPv6Address = customListenAddress;
                    }
                }
            }

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            var localhostCertificate = new X509Certificate2("localhost.pfx");

            // IPv4 channels.
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(listenAddress, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(listenAddress, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTLSChannel(localhostCertificate, new IPEndPoint(listenAddress, SIPS_LISTEN_PORT)));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.Any, SIP_WEBSOCKET_LISTEN_PORT));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.Any, SIP_SECURE_WEBSOCKET_LISTEN_PORT, localhostCertificate));

            // IPv6 channels.
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(listenIPv6Address, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(listenIPv6Address, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTLSChannel(localhostCertificate, new IPEndPoint(listenIPv6Address, SIPS_LISTEN_PORT)));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.IPv6Any, SIP_WEBSOCKET_LISTEN_PORT));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.IPv6Any, SIP_SECURE_WEBSOCKET_LISTEN_PORT, localhostCertificate));

            EnableTraceLogs(sipTransport);

            string executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            // To keep things a bit simpler this example only supports a single call at a time and the SIP server user agent
            // acts as a singleton
            SIPServerUserAgent      uas        = null;
            CancellationTokenSource rtpCts     = null; // Cancellation token to stop the RTP stream.
            RtpAVSession            rtpSession = null;

            // Because this is a server user agent the SIP transport must start listening for client user agents.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                try
                {
                    if (sipRequest.Method == SIPMethodsEnum.INVITE)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation($"Incoming call request: {localSIPEndPoint}<-{remoteEndPoint} {sipRequest.URI}.");

                        // Check there's a codec we support in the INVITE offer.
                        var        offerSdp       = SDP.ParseSDPDescription(sipRequest.Body);
                        IPEndPoint dstRtpEndPoint = SDP.GetSDPRTPEndPoint(sipRequest.Body);

                        if (offerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.HasMediaFormat((int)SDPMediaFormatsEnum.PCMU)))
                        {
                            Log.LogDebug($"Client offer contained PCMU audio codec.");
                            rtpSession = new RtpAVSession(
                                new AudioOptions {
                                AudioSource = AudioSourcesEnum.Music, SourceFile = executableDir + "/" + AUDIO_FILE_PCMU
                            }, null);
                            rtpSession.setRemoteDescription(new RTCSessionDescription {
                                type = RTCSdpType.offer, sdp = offerSdp
                            });
                        }

                        if (rtpSession == null)
                        {
                            // Didn't get a match on the codecs we support.
                            SIPResponse noMatchingCodecResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptableHere, null);
                            await sipTransport.SendResponseAsync(noMatchingCodecResponse);
                        }
                        else
                        {
                            // If there's already a call in progress hang it up. Of course this is not ideal for a real softphone or server but it
                            // means this example can be kept simpler.
                            if (uas?.IsHungup == false)
                            {
                                uas?.Hangup(false);
                            }
                            rtpCts?.Cancel();
                            rtpCts = new CancellationTokenSource();

                            UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                            uas = new SIPServerUserAgent(sipTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction);
                            uas.CallCancelled += (uasAgent) =>
                            {
                                rtpCts?.Cancel();
                                rtpSession.CloseSession(null);
                            };
                            rtpSession.OnRtpClosed += (reason) => uas?.Hangup(false);
                            uas.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null);
                            uas.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null);

                            var answerSdp = await rtpSession.createAnswer(null);

                            uas.Answer(SDP.SDP_MIME_CONTENTTYPE, answerSdp.ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);

                            await rtpSession.Start();
                        }
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.BYE)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation("Call hungup.");
                        SIPResponse byeResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        await sipTransport.SendResponseAsync(byeResponse);

                        uas?.Hangup(true);
                        rtpSession?.CloseSession(null);
                        rtpCts?.Cancel();
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.SUBSCRIBE)
                    {
                        SIPResponse notAllowededResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                        await sipTransport.SendResponseAsync(notAllowededResponse);
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.OPTIONS || sipRequest.Method == SIPMethodsEnum.REGISTER)
                    {
                        SIPResponse optionsResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        await sipTransport.SendResponseAsync(optionsResponse);
                    }
                }
                catch (Exception reqExcp)
                {
                    SIPSorcery.Sys.Log.Logger.LogWarning($"Exception handling {sipRequest.Method}. {reqExcp.Message}");
                }
            };

            ManualResetEvent exitMre = new ManualResetEvent(false);

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;

                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");

                Hangup(uas).Wait();

                rtpSession?.CloseSession(null);
                rtpCts?.Cancel();

                if (sipTransport != null)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                    sipTransport.Shutdown();
                }

                exitMre.Set();
            };

            // Task to handle user key presses.
            Task.Run(() =>
            {
                try
                {
                    while (!exitMre.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();
                        if (keyProps.KeyChar == 'h' || keyProps.KeyChar == 'q')
                        {
                            Console.WriteLine();
                            Console.WriteLine("Hangup requested by user...");

                            Hangup(uas).Wait();

                            rtpSession?.CloseSession(null);
                            rtpCts?.Cancel();
                        }

                        if (keyProps.KeyChar == 'q')
                        {
                            SIPSorcery.Sys.Log.Logger.LogInformation("Quitting...");

                            if (sipTransport != null)
                            {
                                SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                                sipTransport.Shutdown();
                            }

                            exitMre.Set();
                        }
                    }
                }
                catch (Exception excp)
                {
                    SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            exitMre.WaitOne();
        }
예제 #31
0
 public void Warn(string message, params object[] args)
 {
     _internalLogger.LogWarning(message, args);
 }