private PushChannel AChannel(int queuedEventCount)
 {
     var channelEvents = new ChannelEvents();
     var theChannel = Substitute.For<PushChannel>();
     theChannel.Events.Returns(channelEvents);
     theChannel.QueuedNotificationCount.Returns(queuedEventCount);
     return theChannel;
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Bridge a new channel to the existing one. Generally used to route an incoming call to one or more endpoints.
        /// </summary>
        /// <remarks>
        /// See https://freeswitch.org/confluence/display/FREESWITCH/bridge
        /// </remarks>
        /// <param name="uuid">The UUID of the channel to bridge (the A-Leg).</param>
        /// <param name="endpoint">The destination to dial.</param>
        /// <param name="options">(Optional) Any <seealso cref="BridgeOptions"/> to configure the bridge.</param>
        /// <returns>A Task of <seealso cref="BridgeResult"/>.</returns>
        public async Task <BridgeResult> Bridge(string uuid, string endpoint, BridgeOptions options = null)
        {
            if (options == null)
            {
                options = new BridgeOptions();
            }

            if (string.IsNullOrEmpty(options.UUID))
            {
                options.UUID = Guid.NewGuid().ToString();
            }

            var bridgeString = string.Format("{0}{1}", options, endpoint);

            // some bridge options need to be set in channel vars
            if (options.ChannelVariables.Any())
            {
                await
                this.SetMultipleChannelVariables(
                    uuid, options.ChannelVariables.Select(kvp => kvp.Key + "='" + kvp.Value + "'").ToArray()).ConfigureAwait(false);
            }

            /* If the bridge fails to connect we'll get a CHANNEL_EXECUTE_COMPLETE event with a failure message and the Execute task will complete.
             * If the bridge succeeds, that event won't arrive until after the bridged leg hangs up and completes the call.
             * In this case, we want to return a result as soon as the b-leg picks up and connects so we'll merge with the CHANNEL_BRIDGE event
             * observable.Amb(otherObservable) will propogate the first sequence to produce a result. */

            await SubscribeEvents(EventName.ChannelBridge, EventName.ChannelHangup).ConfigureAwait(false);

            var bridgedOrHungupEvent =
                ChannelEvents.FirstOrDefaultAsync(x => x.UUID == uuid && (x.EventName == EventName.ChannelBridge || x.EventName == EventName.ChannelHangup))
                .Do(
                    e =>
            {
                if (e != null)
                {
                    switch (e.EventName)
                    {
                    case EventName.ChannelBridge:
                        Console.WriteLine("Bridge [{0} - {1}] complete - {2}".Fmt(uuid, options.UUID, e.Headers[HeaderNames.OtherLegUniqueId]));
                        break;

                    case EventName.ChannelHangup:
                        Console.WriteLine("Bridge [{0} - {1}]  aborted, channel hangup [{2}]".Fmt(uuid, options.UUID, e.Headers[HeaderNames.HangupCause]));
                        break;
                    }
                }
            });

            return
                (await
                 ExecuteApplication(uuid, "bridge", bridgeString)
                 .ToObservable()
                 .Amb(bridgedOrHungupEvent)
                 .Select(x => new BridgeResult(x))
                 .ToTask()
                 .ConfigureAwait(false));
        }
Ejemplo n.º 3
0
        public void VirtualChannelOpenEvent(int openHandle, ChannelEvents Event, IntPtr pData, int dataLength, uint totalLength, ChannelFlags dataFlags)
        {
            Debug.Print(DateTime.Now + " " + Environment.MachineName + ": VirtualChannelOpenEvent: " + Event);
            switch (Event)
            {
            case ChannelEvents.DataReceived:
                var data = new byte[dataLength];
                Marshal.Copy(pData, data, 0, dataLength);
                switch (dataFlags & ChannelFlags.Only)
                {
                case ChannelFlags.Only:
                    MessageReceived(ChannelMessage.FromByteArray(data));
                    break;

                case ChannelFlags.First:
                    memoryStream = new MemoryStream((int)totalLength);
                    memoryStream.Write(data, 0, data.Length);
                    break;

                case ChannelFlags.Middle:
                    if (memoryStream != null)
                    {
                        memoryStream.Write(data, 0, data.Length);
                    }
                    break;

                case ChannelFlags.Last:
                    if (memoryStream != null)
                    {
                        memoryStream.Write(data, 0, data.Length);
                        memoryStream.Position = 0;
                        MessageReceived(ChannelMessage.FromStream(memoryStream));
                        memoryStream = null;
                    }
                    break;
                }
                break;

            case ChannelEvents.WriteCanceled:
            case ChannelEvents.WriteComplete:
                /*
                 * The VirtualChannelWrite function is asynchronous. When the write operation has been completed,
                 * your VirtualChannelOpenEvent function receives a CHANNEL_EVENT_WRITE_COMPLETE notification.
                 * Until that notification is received, the caller must not free or reuse the pData buffer passed to VirtualChannelWrite
                 */
                Marshal.FreeHGlobal(pData);
                break;
            }
        }
        public void GivenAQueueBalancer()
        {
            var channelEvents = new ChannelEvents();
            this.eventsProxy = new ChannelEvents();
            this.eventsProxy.OnChannelCreated += this.eventsProxyOnChannelCreated;

            var channelFactory = Substitute.For<ChannelFactory>();
            var channel = Substitute.For<PushChannel>();
            channel.Events.Returns(channelEvents);
            channelFactory.Create().Returns(channel);

            this.balancer = new QueueLengthLoadBalancer(channelFactory, this.eventsProxy, PlatformType.None);

            this.balancer.AddChannels(5);
        }
        public void WhenBalancerIsShutdown()
        {
            var channelEvents = new ChannelEvents();
            this.eventsProxy = new ChannelEvents();

            var channelFactory = Substitute.For<ChannelFactory>();
            this.theChannel = Substitute.For<PushChannel>();
            this.theChannel.Events.Returns(channelEvents);
            channelFactory.Create().Returns(this.theChannel);

            this.balancer = new QueueLengthLoadBalancer(channelFactory, this.eventsProxy, PlatformType.None);

            this.balancer.AddChannels(1);
            this.balancer.ShutdownAll(true);
        }
        public void WhenTwoChannelsAreRemoved()
        {
            var channelEvents = new ChannelEvents();
            this.eventsProxy = new ChannelEvents();
            this.eventsProxy.OnChannelDestroyed += this.EventsProxyOnChannelDestroyed;

            var channelFactory = Substitute.For<ChannelFactory>();
            var channel = Substitute.For<PushChannel>();
            channel.Events.Returns(channelEvents);
            channelFactory.Create().Returns(channel);

            this.balancer = new QueueLengthLoadBalancer(channelFactory, this.eventsProxy, PlatformType.None);

            this.balancer.AddChannels(3);
            this.balancer.RemoveChannels(5);
        }
        public void VirtualChannelOpenEvent(int openHandle,
                                            ChannelEvents Event, byte[] data,
                                            int dataLength, uint totalLength, ChannelFlags dataFlags)
        {
            DataChannelEventArgs args = new DataChannelEventArgs()
            {
                Data        = data,
                DataFlags   = dataFlags,
                DataLength  = dataLength,
                Event       = Event,
                OpenHandle  = openHandle,
                TotalLength = totalLength
            };

            OnDataChannelEvent(args);
        }
Ejemplo n.º 8
0
        public Base(Negotiation.Base parent, Message.Negotiation.Parameters parameters, UnityAction <Base> disconnection_handler)
        {
            this.parent     = parent;
            this.parameters = parameters;

            events = new ChannelEvents();
            events.onDisconnectedHandler = new ChannelEvents.DisonnectionHandlerCallback();
            events.onDisconnectedHandler.AddListener(disconnection_handler);

            sendResult = null;

            sendQueue = new Queue <Threads.Task>();

            stopEvent = new ManualResetEvent(false);
            addEvent  = new ManualResetEvent(false);

            worker = new Threads.Thread(Worker);
        }
        public void WhenBalancerIsShutdown()
        {
            this.eventsProxy = new ChannelEvents();

            var channelFactory = Substitute.For<ChannelFactory>();

            this.GivenAnEmptyChannel();
            this.GivenABusyChannel();

            channelFactory.Create().Returns(this.theEmptyChannel, theBusyChannel);

            this.balancer = new QueueLengthLoadBalancer(channelFactory, this.eventsProxy, PlatformType.None);

            this.theNotification = Substitute.For<Notification>();

            this.balancer.AddChannels(2);
            this.balancer.Distribute(this.theNotification);
        }
Ejemplo n.º 10
0
        private void VirtualChannelInitEventProc(IntPtr initHandle, ChannelEvents Event, byte[] data, int dataLength)
        {
            Debug.Print(DateTime.Now + " " + Environment.MachineName + ": VirtualChannelInitEventProc: " + Event);
            switch (Event)
            {
            case ChannelEvents.Initialized:
                break;

            case ChannelEvents.Connected:
                var ret = entryPoints.VirtualChannelOpen(initHandle, ref OpenChannel, ChannelMessage.ChannelName, channelOpenEventDelegate);
                if (ret != ChannelReturnCodes.Ok)
                {
                    MessageBox.Show("TSTunnels: Open of RDP virtual channel failed.\n" + ret, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    /*main = new frmMain(entryPoints, OpenChannel);
                     * main.Show();
                     * main.Hide();
                     * string servername = System.Text.Encoding.Unicode.GetString(data);
                     * servername = servername.Substring(0, servername.IndexOf('\0'));
                     * main.Text = "TS addin in C#: " + servername;*/
                }
                break;

            case ChannelEvents.V1Connected:
                MessageBox.Show("TSTunnels: Connecting to a non Windows 2000 Terminal Server.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                break;

            case ChannelEvents.Disconnected:
                //main.RealClosing = true;
                //main.Close();
                break;

            case ChannelEvents.Terminated:
                break;
            }
        }
        public void VirtualChannelInitEventProc(IntPtr initHandle,
                                                ChannelEvents Event, byte[] data, int dataLength)
        {
            switch (Event)
            {
            case ChannelEvents.Initialized:
                break;

            case ChannelEvents.Connected:
                ChannelReturnCodes ret = _entryPoints.VirtualChannelOpen(
                    initHandle, ref _openChannel,
                    _channelName, _channelOpenEventDelegate);
                if (ret != ChannelReturnCodes.Ok)
                {
                    throw new VirtualChannelException(String.Format("TsClientAddIn ({0}): Couldn't open communcation channel for battery monitor.", _channelName));
                }
                else
                {
                    string servername = System.Text.Encoding.Unicode.GetString(data);
                    _serverName = servername.Substring(0, servername.IndexOf('\0'));
                }
                break;

            case ChannelEvents.V1Connected:
                throw new VirtualChannelException(String.Format("TsClientAddIn ({0}): Connecting to a Terminal Server that doesn't support data communication.", _channelName));

            case ChannelEvents.Disconnected:
                break;

            case ChannelEvents.Terminated:
                GC.KeepAlive(_channelInitEventDelegate);
                GC.KeepAlive(_channelOpenEventDelegate);
                GC.KeepAlive(_entryPoints);
                GC.Collect();
                GC.WaitForPendingFinalizers();
                break;
            }
        }
Ejemplo n.º 12
0
 public PushService()
 {
     this.Events = new ChannelEvents();
 }
Ejemplo n.º 13
0
 /// <summary>
 /// Register a callback to be invoked when the given Channel UUID hangs up.
 /// </summary>
 /// <param name="uuid">The Channel UUID.</param>
 /// <param name="action">A Callback to be invoked on hangup.</param>
 public void OnHangup(string uuid, Action <EventMessage> action)
 {
     ChannelEvents.Where(x => x.UUID == uuid && x.EventName == EventName.ChannelHangup).Take(1).Subscribe(action);
 }
Ejemplo n.º 14
0
        /// <summary>
        /// Asynchronously executes a dialplan application on the given channel.
        /// </summary>
        /// <remarks>
        /// See https://freeswitch.org/confluence/display/FREESWITCH/mod_dptools
        /// </remarks>
        /// <param name="uuid">The channel UUID.</param>
        /// <param name="application">The dialplan application to execute.</param>
        /// <param name="applicationArguments">(Optional) arguments to pass to the application.</param>
        /// <param name="eventLock">(Default: false) Whether to block the socket until the application completes before processing further.
        ///  (see https://wiki.freeswitch.org/wiki/Event_Socket_Outbound#Q:_Ordering_and_async_keyword )</param>
        /// <param name="async">(Default: false) Whether to return control from the application immediately.
        /// (see https://wiki.freeswitch.org/wiki/Event_Socket_Outbound#Q:_Should_I_use_sync_mode_or_async_mode.3F)
        /// </param>
        /// <param name="loops">(Optional) How many times to repeat the application.</param>
        /// <returns>
        /// A Task of <seealso cref="EventMessage"/> that wraps the ChannelExecuteComplete event if the application completes successfully.
        /// The Task result will be null if the application did not execute, for example, the socket disconnected or the channel was hung up.
        /// </returns>
        public Task <ChannelEvent> ExecuteApplication(
            string uuid, string application, string applicationArguments = null, bool eventLock = false, bool async = false, int loops = 1)
        {
            if (uuid == null)
            {
                throw new ArgumentNullException("uuid");
            }

            if (application == null)
            {
                throw new ArgumentNullException("application");
            }

            //lists.freeswitch.org/pipermail/freeswitch-users/2013-May/095329.html
            var applicationUUID = Guid.NewGuid().ToString();

            var sb = StringBuilderPool.Allocate();

            sb.AppendFormat("sendmsg {0}\nEvent-UUID: {1}\ncall-command: execute\nexecute-app-name: {2}\n", uuid, applicationUUID, application);

            if (eventLock)
            {
                sb.Append("event-lock: true\n");
            }

            if (loops > 1)
            {
                sb.Append("loops: " + loops + "\n");
            }

            if (async)
            {
                sb.Append("async: true\n");
            }

            if (applicationArguments != null)
            {
                sb.AppendFormat("content-type: text/plain\ncontent-length: {0}\n\n{1}\n", applicationArguments.Length, applicationArguments);
            }

            var tcs           = new TaskCompletionSource <ChannelEvent>();
            var subscriptions = new CompositeDisposable();

            if (cts.Token.CanBeCanceled)
            {
                subscriptions.Add(cts.Token.Register(() => tcs.TrySetCanceled()));
            }

            subscriptions.Add(
                ChannelEvents.Where(
                    x => x.EventName == EventName.ChannelExecuteComplete && x.Headers["Application-UUID"] == applicationUUID)
                .Take(1)
                .Subscribe(
                    executeCompleteEvent =>
            {
                if (executeCompleteEvent != null)
                {
                    Console.WriteLine("{0} ChannelExecuteComplete [{1} {2} {3}]".Fmt(
                                          executeCompleteEvent.UUID,
                                          executeCompleteEvent.AnswerState,
                                          executeCompleteEvent.Headers[HeaderNames.Application],
                                          executeCompleteEvent.Headers[HeaderNames.ApplicationResponse]));
                }
                else
                {
                    Console.WriteLine("No ChannelExecuteComplete event received for {0}".Fmt(application));
                }

                tcs.TrySetResult(executeCompleteEvent);
            },
                    ex => tcs.TrySetException(ex),
                    subscriptions.Dispose));

            SubscribeEvents(EventName.ChannelExecuteComplete).ContinueWith(t =>
            {
                if (t.IsCompleted)
                {
                    SendCommand(StringBuilderPool.ReturnAndFree(sb))
                    .Then(reply =>
                    {
                        if (!reply.Success)
                        {
                            tcs.TrySetResult(null);
                        }
                    })
                    .ContinueOnFaultedOrCancelled(tcs, subscriptions.Dispose);
                }
                else
                {
                    tcs.TrySetException(t.Exception);
                }
            });

            return(tcs.Task);
        }