Exemple #1
0
        public void HandleSendable(Sendable sendable)
        {
            throwExceptionIfMissiongSetupCall();

            if (sendable is Message message)
            {
                if (base.moduleType == message.TargetModuleType)
                {
                    //handle request
                    HandleRequest(message);
                }
                else
                {
                    //forward the message
                    ForwardSendable(message);
                }
            }
            else if (sendable is Response response)
            {
                if (base.moduleID == response.IntendedTargetModuleID)
                {
                    //response for self
                    //HandleResponse(response);
                    throw new Exception("Do I need this?");
                }
                else
                {
                    ForwardSendable(response);
                }
            }
        }
Exemple #2
0
        /** Called by the Listener to process a received message. See if this
         * is a response and correlate with requests if it is, otherwise add
         * to the received messages queue. This is called by Listener.processMessage()
         * which is invoked in its own thread, so we don't need to spawn any new
         * threads here.
         *
         * @param Received message
         */
        internal void receive(Sendable s)
        {
            if (s.SoapAction.Contains("service:Acknowledgment") || s.SoapAction.Contains("service:MessageError"))
            {
                // Asynchronous ack/nack. Remove from request list and exit.
                //
                EbXmlMessage m = (EbXmlMessage)s;
                if (!requests.Remove(m.Header.ConversationId))
                {
                    // Log receipt of ack/nack that doesn't belong to us...
                    // Note: This may be legitimate in a clustered MHS or if in- and out-bound
                    // nodes are separate.
                    //
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    StringBuilder sbe = new StringBuilder("Unexpected response ");
                    sbe.Append(s.SoapAction);
                    sbe.Append(" with conversation id ");
                    sbe.Append(m.Header.ConversationId);
                    sbe.Append(" that was not sent from here.");
                    logger.WriteEntry(sbe.ToString(), EventLogEntryType.Information);
                }

                depersist(m.Header.ConversationId);
                return;
            }
            ISpineHandler h = null;

            try
            {
                h = handlers[s.SoapAction];
            }
            catch (KeyNotFoundException)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                StringBuilder sbe = new StringBuilder("Unknown SOAP action ");
                sbe.Append(s.SoapAction);
                sbe.Append(" using DefaultFileSaveSpineHandler");
                logger.WriteEntry(sbe.ToString(), EventLogEntryType.FailureAudit);
                h = defaultSpineHandler;
            }
            try
            {
                h.handle(s);
            }
            catch (Exception e)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                StringBuilder sbe = new StringBuilder("Exception handling  ");
                sbe.Append(s.SoapAction);
                sbe.Append(" : ");
                sbe.Append(e.ToString());
                logger.WriteEntry(sbe.ToString(), EventLogEntryType.FailureAudit);
            }
        }
Exemple #3
0
        protected void ForwardSendable(Sendable sendable)
        {
            throwExceptionIfMissiongSetupCall();

            if (sendable is Message message)
            {
                this.moduleTypeToProxyHelper[message.TargetModuleType].ReciveSendable(sendable);
            }
            else if (sendable is Response response)
            {
                this.moduleIdToProxyHelper[response.IntendedTargetModuleID].ReciveSendable(sendable);
            }
        }
Exemple #4
0
        public async Task Process(BitmapDecoder decoder)
        {
            var bitmaps = await Split(decoder);

            bitmaps.AsParallel().ForAll(async k =>
            {
                foreach (var light in Map.Blocks[k.Key].AffectedLights)
                {
                    var color = await GetColorFromBitmap(k.Value);
                    await Sendable.SendColorAsync(light.Id, color);
                }
            });
        }
Exemple #5
0
 /**
  * Wrapper round the transmission and, where relevant retry and receipt of an asynchronous
  * response, for a "Sendable" message using the given transmission details resolved either
  * from SDS or the local SDS cache. This does the actual transmission in a separate thread
  * so will return immediately.
  *
  * @param Sendable s Message to send
  * @param SdsTransmissionDetails c retrieved transmission details for the message type/recipient pair
  */
 public void send(Sendable s, SdsTransmissionDetails c)
 {
     if (!c.IsSynchronous)
     {
         listen();
         // Don't expect an ack if we're sending an asynchronous ack, but otherwise do
         // do that we have something to attach a response to, if we're going to get one.
         //
         if (!(s.Type == Sendable.ACK) && (c.DuplicateElimination.Equals("always")))
         {
             if (!requests.ContainsKey(s.getMessageId()))
             {
                 requests.Add(s.getMessageId(), s);
             }
         }
     }
     (new Thread(() => this.doTransmission(s))).Start();
 }
Exemple #6
0
        /**
         * Internal method to transmit a Sendable message, called by send() and by the retry mechanism.
         * This handles:
         * - de-queueing reliable messages that have been acknowledged synchronously (or for which an explicit error has been received),
         * - collecting any synchronous response which is stored in the SynchronousResponse property of the Sendable instance.
         * - calling the response handler for synchronous requests
         * - error logging
         *
         * Note that due to a design error in SDS not all target endpoint URLs are resolvable from SDS:
         * "forwarded" messages for which Spine is an intermediary must resolve the endpoint URL some
         * other way. See the SDSconnection API documentation for how this is configured.
         *
         * @param Message to transmit
         */
        private void doTransmission(Sendable s)
        {
            // Create a socket and then do the TLS over it to
            // make an SSL stream. Then write the Sendable down the stream and get any
            // "stuff" back synchronously. If we do get a synchronous ack, remove the
            // reference to the transmitted message from "requests".
            //
            Socket clearSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // Note this uses the "ResolvedUrl" from the Sendable, not the "Url" from SDS because the
            // SDS data will be broken by design for "forwarded" services.
            //

            // TODO NEXT: Persist and send from persisted message
            string host         = null;
            string syncresponse = null;

            if (s.ResolvedUrl == null)
            {
                // Sending persisted, reloaded message
                host = ((EbXmlMessage)s).getHost();
                clearSocket.Connect(host, HTTPS);
            }
            else
            {
                // "Primary" transmission
                s.persist();
                Uri uri = new Uri(s.ResolvedUrl);
                host = uri.Host;
                if (uri.Port == -1)
                {
                    clearSocket.Connect(uri.Host, HTTPS);
                }
                else
                {
                    clearSocket.Connect(host, uri.Port);
                }
            }
            if (!s.recordTry())
            {
                if (s.getMessageId() != null)
                {
                    removeRequest((EbXmlMessage)s);
                    s.Expire();
                }
                return;
            }
            string httpResponseLine = null;

            using (NetworkStream n = new NetworkStream(clearSocket))
            {
                SslStream ssl = new SslStream(n, false, validateRemoteCertificate, new LocalCertificateSelectionCallback(getLocalCertificate));
                //ssl.AuthenticateAsClient(host);
                ssl.AuthenticateAsClient(host, endpointCertificateCollection, SslProtocols.Tls, true);
                if (!ssl.IsAuthenticated || !ssl.IsSigned || !ssl.IsEncrypted)
                {
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    logger.WriteEntry("Failed to authenticate SSL connection", EventLogEntryType.Error);
                    throw new Exception("Failed to authenticate SSL connection");
                }
                s.write(ssl);
                ssl.Flush();
                // Read any response ...
                // ... first line first...
                httpResponseLine = readline(ssl);
                // ... then the rest of it
                int contentlength = getHeader(ssl);
                if (contentlength == -1)
                {
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    logger.WriteEntry("Failed to read response content length", EventLogEntryType.Error);
                    return;
                }
                // Process response and add it to the Sendable - Spine synchronous responses are all fairly
                // small, even for with-history retrievals
                if (contentlength > 0)
                {
                    int    read   = 0;
                    byte[] buffer = new byte[contentlength];
                    do
                    {
                        int r = ssl.Read(buffer, read, contentlength - read);
                        if (r == -1)
                        {
                            EventLog logger = new EventLog("Application");
                            logger.Source = LOGSOURCE;
                            logger.WriteEntry("Premature EOF sending " + s.getMessageId(), EventLogEntryType.Error);
                            break;
                        }
                        read += r;
                    } while (read < contentlength);
                    syncresponse = Encoding.UTF8.GetString(buffer);
                }
            }
            s.SyncronousResponse = syncresponse;
            if (s.Type == Sendable.SOAP)
            {
                if (synchronousHandlers.ContainsKey(s.SoapAction))
                {
                    ISynchronousResponseHandler h = synchronousHandlers[s.SoapAction];
                    h.handle((SpineSOAPRequest)s);
                }
                else
                {
                    defaultSynchronousResponseHandler.handle((SpineSOAPRequest)s);
                }
                return;
            }
            // "Don't listen for any response" conditions where we remove this message from the
            // current set of things-we're-waiting-on-responses-for are:
            // Explicit error (HTTP 500)
            // A synchronous ebXML response (Acknowledgement or MessageError) with our message id in it.
            //
            // Note: The contract properties in SDS are a mess, so don't bother trying to infer behaviour
            // from them.
            //
            if (s.getMessageId() != null) // Don't try for acks.
            {
                if (s.SyncronousResponse != null)
                {
                    if (httpResponseLine.Contains("HTTP 5") || (s.SyncronousResponse.Contains(s.getMessageId())))
                    {
                        removeRequest((EbXmlMessage)s);
                    }
                }
            }
        }
        /**
         * Internal method to transmit a Sendable message, called by send() and by the retry mechanism.
         * This handles:
         * - de-queueing reliable messages that have been acknowledged synchronously (or for which an explicit error has been received),
         * - collecting any synchronous response which is stored in the SynchronousResponse property of the Sendable instance.
         * - calling the response handler for synchronous requests
         * - error logging
         *
         * Note that due to a design error in SDS not all target endpoint URLs are resolvable from SDS:
         * "forwarded" messages for which Spine is an intermediary must resolve the endpoint URL some
         * other way. See the SDSconnection API documentation for how this is configured.
         *
         * @param Message to transmit
         */
        private void doTransmission(Sendable s)
        {
            // Create a socket and then do the TLS over it to
            // make an SSL stream. Then write the Sendable down the stream and get any
            // "stuff" back synchronously. If we do get a synchronous ack, remove the
            // reference to the transmitted message from "requests".
            //
            Socket clearSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // Note this uses the "ResolvedUrl" from the Sendable, not the "Url" from SDS because the
            // SDS data will be broken by design for "forwarded" services.
            //

            // TODO NEXT: Persist and send from persisted message
            string host = null;
            string syncresponse = null;
            if (s.ResolvedUrl == null)
            {
                // Sending persisted, reloaded message
                host = ((EbXmlMessage)s).getHost();
                clearSocket.Connect(host, HTTPS);
            }
            else
            {
                // "Primary" transmission
                s.persist();
                Uri uri = new Uri(s.ResolvedUrl);
                host = uri.Host;
                if (uri.Port == -1)
                    clearSocket.Connect(uri.Host, HTTPS);
                else
                    clearSocket.Connect(host, uri.Port);
            }
            if (!s.recordTry())
            {
                if (s.getMessageId() != null)
                {
                    removeRequest((EbXmlMessage)s);
                    s.Expire();
                }
                return;
            }
            string httpResponseLine = null;
            using (NetworkStream n = new NetworkStream(clearSocket))
            {
                SslStream ssl = new SslStream(n, false, validateRemoteCertificate, new LocalCertificateSelectionCallback(getLocalCertificate));
                //ssl.AuthenticateAsClient(host);
                ssl.AuthenticateAsClient(host, endpointCertificateCollection, SslProtocols.Tls, true);
                if (!ssl.IsAuthenticated || !ssl.IsSigned || !ssl.IsEncrypted)
                {
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    logger.WriteEntry("Failed to authenticate SSL connection", EventLogEntryType.Error);
                    throw new Exception("Failed to authenticate SSL connection");
                }
                s.write(ssl);
                ssl.Flush();
                // Read any response ...
                // ... first line first...
                httpResponseLine = readline(ssl);
                // ... then the rest of it
                int contentlength = getHeader(ssl);
                if (contentlength == -1)
                {
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    logger.WriteEntry("Failed to read response content length", EventLogEntryType.Error);
                    return;
                }
                // Process response and add it to the Sendable - Spine synchronous responses are all fairly
                // small, even for with-history retrievals
                if (contentlength > 0)
                {
                    int read = 0;
                    byte[] buffer = new byte[contentlength];
                    do
                    {
                        int r = ssl.Read(buffer, read, contentlength - read);
                        if (r == -1)
                        {
                            EventLog logger = new EventLog("Application");
                            logger.Source = LOGSOURCE;
                            logger.WriteEntry("Premature EOF sending " + s.getMessageId(), EventLogEntryType.Error);
                            break;
                        }
                        read += r;
                    } while (read < contentlength);
                    syncresponse = Encoding.UTF8.GetString(buffer);
                }
            }
            s.SyncronousResponse = syncresponse;
            if (s.Type == Sendable.SOAP)
            {
                if (synchronousHandlers.ContainsKey(s.SoapAction))
                {
                    ISynchronousResponseHandler h = synchronousHandlers[s.SoapAction];
                    h.handle((SpineSOAPRequest)s);
                }
                else
                {
                    defaultSynchronousResponseHandler.handle((SpineSOAPRequest)s);
                }
                return;
            }
            // "Don't listen for any response" conditions where we remove this message from the
            // current set of things-we're-waiting-on-responses-for are:
            // Explicit error (HTTP 500)
            // A synchronous ebXML response (Acknowledgement or MessageError) with our message id in it.
            //
            // Note: The contract properties in SDS are a mess, so don't bother trying to infer behaviour
            // from them.
            //
            if (s.getMessageId() != null) // Don't try for acks.
            {
                if (s.SyncronousResponse != null)
                {
                    if (httpResponseLine.Contains("HTTP 5") || (s.SyncronousResponse.Contains(s.getMessageId())))
                        removeRequest((EbXmlMessage)s);
                }
            }
        }
        /** Called by the Listener to process a received message. See if this
         * is a response and correlate with requests if it is, otherwise add
         * to the received messages queue. This is called by Listener.processMessage()
         * which is invoked in its own thread, so we don't need to spawn any new
         * threads here.
         *
         * @param Received message
        */
        internal void receive(Sendable s)
        {
            if (s.SoapAction.Contains("service:Acknowledgment") || s.SoapAction.Contains("service:MessageError"))
            {
                // Asynchronous ack/nack. Remove from request list and exit.
                //
                EbXmlMessage m = (EbXmlMessage)s;
                if (!requests.Remove(m.Header.ConversationId))
                {
                    // Log receipt of ack/nack that doesn't belong to us...
                    // Note: This may be legitimate in a clustered MHS or if in- and out-bound
                    // nodes are separate.
                    //
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    StringBuilder sbe = new StringBuilder("Unexpected response ");
                    sbe.Append(s.SoapAction);
                    sbe.Append(" with conversation id ");
                    sbe.Append(m.Header.ConversationId);
                    sbe.Append(" that was not sent from here.");
                    logger.WriteEntry(sbe.ToString(), EventLogEntryType.Information);
                }

                depersist(m.Header.ConversationId);
                return;
            }
            ISpineHandler h = null;
            try
            {
                h = handlers[s.SoapAction];
            }
            catch (KeyNotFoundException)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                StringBuilder sbe = new StringBuilder("Unknown SOAP action ");
                sbe.Append(s.SoapAction);
                sbe.Append(" using DefaultFileSaveSpineHandler");
                logger.WriteEntry(sbe.ToString(), EventLogEntryType.FailureAudit);
                h = defaultSpineHandler;
            }
            try
            {
                h.handle(s);
            }
            catch (Exception e)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                StringBuilder sbe = new StringBuilder("Exception handling  ");
                sbe.Append(s.SoapAction);
                sbe.Append(" : ");
                sbe.Append(e.ToString());
                logger.WriteEntry(sbe.ToString(), EventLogEntryType.FailureAudit);
            }
        }
 /**
  * Wrapper round the transmission and, where relevant retry and receipt of an asynchronous
  * response, for a "Sendable" message using the given transmission details resolved either
  * from SDS or the local SDS cache. This does the actual transmission in a separate thread
  * so will return immediately.
  *
  * @param Sendable s Message to send
  * @param SdsTransmissionDetails c retrieved transmission details for the message type/recipient pair
  */
 public void send(Sendable s, SdsTransmissionDetails c)
 {
     if (!c.IsSynchronous)
     {
         listen();
         // Don't expect an ack if we're sending an asynchronous ack, but otherwise do
         // do that we have something to attach a response to, if we're going to get one.
         //
         if (!(s.Type == Sendable.ACK) && (c.DuplicateElimination.Equals("always")))
         {
             if (!requests.ContainsKey(s.getMessageId()))
                 requests.Add(s.getMessageId(), s);
         }
     }
     (new Thread(() => this.doTransmission(s))).Start();
 }