예제 #1
0
        private void DevLink_Received_CallBack(uint pbxh, StringBuilder rawDevLink)                     // CallEvent
        {
            // TODO: TRY - CATCH

            DEBUGLogger.WriteThreadInfo("DevLink_Received_CallBack");

            DEBUGLogger.WriteLine("pbxh=" + pbxh + ";  info=" + rawDevLink);

            _rawDevLinkQueue.Enqueue(new DevLinkMessage()
            {
                IpAddress = IpAddress, RawDevLink = rawDevLink.ToString(), SiteId = _iPOID
            });

            // Make thread-safe: since this method is a CallBack, it will be called by Avaya's DevLink code
            // in its's thread, which will be different from any of the possible subscriber's threads.
            // http://broadcast.oreilly.com/2010/09/understanding-c-raising-events.html
            var devLinkRecieved_threadSafe = DevLinkRecieved;

            // Multi-cast delegates are immutable, so whatever happens to DevLinkRecieved from here on will NOT affect devLinkRecieved_threadSafe
            if (devLinkRecieved_threadSafe != null)
            {
                devLinkRecieved_threadSafe(this, new DevLinkEventArgs((int)pbxh, rawDevLink.ToString()));

                // NOTE:
                // When an event fires, all of the registered handlers execute on the same thread (the one that raised the event -
                // in our case - the thread belongs to Avaya's DevLink!).
                // There's no built-in facility for events to fire on multiple threads.
                // http://stackoverflow.com/questions/3480036/multiple-threads-subscribing-same-event
            }
        }
예제 #2
0
        private void CloseConnection()
        {
            // We may want to call this just in case (when connection timeout expires) so we don't get any more calls back from DevLink!
            if (ConnectionState != ConnectionStates.Disconnected)
            {
                // Disconnect from an IP Office system:
                // This routine may return 0 (DEVLINK_SUCCESS) or 1 (DEVLINK_UNSPECIFIEDFAIL) in the event of an error.
                // [AK:] OR a big number >> 1, in the event it is called twice for the same IPO.
                // TODO: should we check for ret > 0 ???
                long iRet = DLClose((uint)_iPOID);

                ConnectionState = ConnectionStates.Disconnected;

                // TODO: set the callback delegates to NULL???
                // OR Just do NOTHING in the methods, if we are disconnected???

                _disposed = true;
                DEBUGLogger.WriteLine("DLClose:   iPOID = " + _iPOID + ";   iRet = " + iRet);
            }
        }
예제 #3
0
        private void Process()
        {
            DEBUGLogger.WriteThreadInfo("Process");

            _handleDelta2Event = DevLink_Received_CallBack;

            /*This routine may return:-
             *      0 = DEVLINK_SUCCESS
             *      1 = DEVLINK_UNSPECIFIEDFAIL - Returned in the event of an error.
             *      2 = DEVLINK_LICENCENOTFOUND - If no CTI license is activated on the IP Office system. */
            long iRet = DLRegisterType2CallDeltas((uint)_iPOID, _handleDelta2Event // DLCALLLOGEVENT

                                                                                   /*	(pbxh, rawDevLink) => {	lock (thisLock)
                                                                                    *                                                      if (default(EventHandler<DevLinkEventArgs>) != DevLinkRecieved)
                                                                                    *                                                      {
                                                                                    *                                                              DevLinkRecieved(this, new DevLinkEventArgs(pbxh, rawDevLink));
                                                                                    *                                                      } }  */
                                                  );

            DEBUGLogger.WriteLine("DLRegisterType2CallDeltas return value = " + iRet);
        }
예제 #4
0
        /// <summary>
        /// DLOpen callback
        /// </summary>
        /// <param name="pbxh"></param>
        /// <param name="comms_state"></param>
        /// <param name="parm1"></param>
        private void DevLink_Connection_CallBack(uint pbxh, int comms_state, int parm1)                 // oCommsEvent   CommEvent
        {
            DEBUGLogger.WriteThreadInfo("DevLink_Connection_CallBack");

            // TODO: TRY - CATCH
            DEBUGLogger.WriteLine("DevLink_Connection_CallBack:   iPOID = " + pbxh + ";   comms_state = " + comms_state + ";   parm1 = " + parm1);
            if (_ignoreConnectionCallback)
            {
                return;                         // Whatever!
            }
            lock (_connectionLock)
            {
                if (_ignoreConnectionCallback)
                {
                    // It is too late, we have already given up on this method returning!
                    DEBUGLogger.WriteLine("DevLink_Connection_CallBack: Too late, the connection callback result (comms_state=" + comms_state + "; parm1=" + parm1 + ") is being ignored.");
                    return;
                }

                switch ((ConnectionResponse)comms_state)
                {
                // Communications established. This occurs either after the initial call to DLOpen(),
                // or after the  system unit has come back on-line after being powered off or rebooted.
                // TODO: does the above mean that this method will be called again if the system is rebooted...?? Think of how to handle this case!
                case ConnectionResponse.DEVLINK_COMMS_OPERATIONAL_0:
                {
                    ConnectionState = ConnectionStates.Connected;

                    // OK, we're done here, notify the main thread:
                    // TODO: what if this happens before the WaitOne call? OK I guess???
                    _waitConnectionOrTimeoutHandle.Set();
                    return;
                }

                // No response from system unit. This occurs either (1) after the initial call to DLOpen(), or
                // (2) if the system unit is powered off/rebooted, or (3) if network problems prevent communications.
                case ConnectionResponse.DEVLINK_COMMS_NORESPONSE_1:
                {
                    // TODO: LOG a message, and wait more for possible recovery.
                    ConnectionState = ConnectionStates.Failed;
                    return;
                }

                // Reserved for future use OR incorrect system password specified (????)
                case ConnectionResponse.DEVLINK_COMMS_REJECTED_2:
                {
                    _connectionCallbackMessage =
                        "Received response DEVLINK_COMMS_REJECTED - Reserved for future use! Do we have to implement this case too?";
                    break;
                }

                // Packets were generated by IPO, but were not received by DevLink.
                // This can occur either because the IPO is under heavy load (IPPO always prioritizes data routing and call handling above CTI events
                // - parm1 contains the number of packets missed)
                // or because the application using DevLink did not return from a callback quickly enough.
                // Applications should ensure that they do not take more than 100 milliseconds to process events.
                case ConnectionResponse.DEVLINK_COMMS_MISSEDPACKETS_3:
                {
                    _connectionCallbackMessage = "There are " + parm1 +
                                                 " lost packets! IPO may be under heavy load. Ensure that it takes no more than 100 ms to process events!";
                    break;
                }

                default:
                    _connectionCallbackMessage = "Ooops, got unexpected result! comms_state = " + comms_state;
                    break;
                }

                // Hmm, we were not able to connect successfully. We WON'T call _waitConnectionOrTimeoutHandle.Set() now, to give it some more time/chance to connect till the timeout.
                ConnectionState = ConnectionStates.Failed;
            }
        }
예제 #5
0
        private bool StartMonitoring()
        {
            // Start the connecting process. Connecting will be set to FALSE once IsConnected is assigned a value.
            ConnectionState           = ConnectionStates.Connecting;
            _ignoreConnectionCallback = false;
            DEBUGLogger.WriteLine("Waiting for connection response...");


            // Store a reference to the delegate instance in a private class field before passing it to the native code -
            // to prevent the garbage collector from collecting it!
            _handleCommsEvent = DevLink_Connection_CallBack;

            // Create the wait-handle. This thread will wait till the callback returns, or the timeout expires.
            _waitConnectionOrTimeoutHandle = new AutoResetEvent(false);


            // Call the DevLink method to connect:
            long iRet = DLOpen((uint)_iPOID, IpAddress, _password, null, null, _handleCommsEvent);

            // TODO: does it make sense to check for the return value here???
            DEBUGLogger.WriteLine("DLOpen:   iPOID = " + _iPOID + ";   iRet = " + iRet);

            // There is a sliiight possibility that HandleCommsEvent is called and returns before we get to the "...WaitOne()" call below.
            // But we're not going to bother with this - if so, WaitOne will just wait till the timeout.
            // (If we decide to check the ConnectionState here, before calling WaitOne, nothing will prevent it from changing
            // juuust after our check and before the WaitOne call (unless we lock()).)

            // Now wait till the Connection-Callback returns, or the timeout expires:
            _waitConnectionOrTimeoutHandle.WaitOne(_connectionTimeoutSec);                // this should return 'false' in case of timeout, but we don't need the result

            // OK, the event was signaled - let's see what this means for the Connection State...
            lock (_connectionLock)
            {
                if (_connectionCallbackMessage.Length > 0)
                {
                    DEBUGLogger.WriteLine(_connectionCallbackMessage);
                }

                switch (ConnectionState)
                {
                case ConnectionStates.Connected:
                    DEBUGLogger.WriteLine("Connection within timeout!...");
                    break;

                case ConnectionStates.Failed:
                    DEBUGLogger.WriteLine("Connection problems! ConnectionState: " + ConnectionState.ToString());
                    break;

                case ConnectionStates.Connecting:
                    ConnectionState = ConnectionStates.TimedOut;
                    DEBUGLogger.WriteLine("Connection Timeout expired!...");
                    break;

                case ConnectionStates.Disconnected:
                    DEBUGLogger.WriteLine("Unexpected connection state in StartMonitoring() - Disconnected");
                    break;
                }

                // We got a response OR the waiting timed out. Either way, we're done with the CallBack, so let it know:
                _ignoreConnectionCallback = true;
            }                   // un-locking


            if (ConnectionState == ConnectionStates.Connected)
            {
                // Start the DevLink processing:
                // TODO: Maybe move this to the lock..???
                Process();
            }
            else
            {
                // There was a connection error, or we gave up waiting
                // (but DevLink does not know it, and could still call the callback if the timeout interval turned out to be too small)
                // We don't want surprises, so we'd better close the connection, just in case:
                CloseConnection();
            }

            // We should not need this anymore, so close it:
            _waitConnectionOrTimeoutHandle.Close();

            return(ConnectionState == ConnectionStates.Connected);
        }