示例#1
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);
                    }
                }
            }
        }
示例#2
0
 /**
  * Registers an instance of a synchronous response handler, against the SOAPaction of the
  * request message.
  */
 public void addSynchronousResponseHandler(string sa, ISynchronousResponseHandler h)
 {
     synchronousHandlers.Add(sa, h);
 }
 /**
  * Registers an instance of a synchronous response handler, against the SOAPaction of the
  * request message.
  */
 public void addSynchronousResponseHandler(string sa, ISynchronousResponseHandler h)
 {
     synchronousHandlers.Add(sa, h);
 }
示例#4
0
        /**
         * Singleton constructor.
         */
        private ConnectionManager()
        {
            getPasswordProvider();
            requests            = new Dictionary <string, Sendable>();
            expiryHandlers      = new Dictionary <string, IExpiredMessageHandler>();
            handlers            = new Dictionary <string, ISpineHandler>();
            synchronousHandlers = new Dictionary <string, ISynchronousResponseHandler>();
            itkTrunkHandler     = new ITKTrunkHandler();
            handlers.Add("urn:nhs:names:services:itk/COPC_IN000001GB01", itkTrunkHandler);
            handlers.Add("\"urn:nhs:names:services:itk/COPC_IN000001GB01\"", itkTrunkHandler);
            loadCertificate();
            messageDirectory = (string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, MESSAGE_DIRECTORY_REGVAL, "");
            if (messageDirectory.Length == 0)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                logger.WriteEntry("No message directory provided - only in-memory persistence available", EventLogEntryType.Warning);
            }
            // Make sure messageDirectory is terminated with a path delimiter, because we're going
            // to need to add message ids to it when we call depersist() to delete persisted messages
            // on expiry or explicit transmission result.
            //
            if (!messageDirectory.EndsWith("\\"))
            {
                messageDirectory = messageDirectory + "\\";
            }

            myIp = (string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, MY_IP_REGVAL, "");
            if (myIp.Length == 0)
            {
                myIp = null;
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                logger.WriteEntry("No local IP address provided - will use first non-localhost interface", EventLogEntryType.Warning);
            }
            expiredDirectory = (string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, EXPIRED_DIRECTORY_REGVAL, "");
            if (expiredDirectory.Length == 0)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                logger.WriteEntry("No expired message directory provided - administrative handling of unsent messages NOT available", EventLogEntryType.Warning);
            }
            sdsConnection = new SDSconnection();
            try
            {
                retryCheckPeriod = Int64.Parse((string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, RETRY_TIMER_PERIOD_REGVAL, ""));
            }
            catch { }

            string nulldefault = (string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, USE_NULL_DEFAULT_SYNCHRONOUS_HANDLER_REGVAL, "");

            if (nulldefault.ToLower().StartsWith("y"))
            {
                defaultSynchronousResponseHandler = new NullSynchronousResponseHandler();
            }
            else
            {
                defaultSynchronousResponseHandler = new DefaultFileSaveSynchronousResponseHandler();
            }
            defaultSpineHandler = new DefaultFileSaveSpineHandler();

            persistDurations = loadReceivedPersistDurations();
            if (retryCheckPeriod != 0)
            {
                retryProcessorTimer = new Timer(processRetries, null, retryCheckPeriod, retryCheckPeriod);
            }
        }
        /**
         * Singleton constructor.
         */
        private ConnectionManager()
        {
            getPasswordProvider();
            requests = new Dictionary<string, Sendable>();
            expiryHandlers = new Dictionary<string, IExpiredMessageHandler>();
            handlers = new Dictionary<string, ISpineHandler>();
            synchronousHandlers = new Dictionary<string, ISynchronousResponseHandler>();
            itkTrunkHandler = new ITKTrunkHandler();
            handlers.Add("urn:nhs:names:services:itk/COPC_IN000001GB01", itkTrunkHandler);
            handlers.Add("\"urn:nhs:names:services:itk/COPC_IN000001GB01\"", itkTrunkHandler);
            loadCertificate();
            messageDirectory = (string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, MESSAGE_DIRECTORY_REGVAL, "");
            if (messageDirectory.Length == 0)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                logger.WriteEntry("No message directory provided - only in-memory persistence available", EventLogEntryType.Warning);
            }
            // Make sure messageDirectory is terminated with a path delimiter, because we're going
            // to need to add message ids to it when we call depersist() to delete persisted messages
            // on expiry or explicit transmission result.
            //
            if (!messageDirectory.EndsWith("\\"))
                messageDirectory = messageDirectory + "\\";

            myIp = (string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, MY_IP_REGVAL, "");
            if (myIp.Length == 0)
            {
                myIp = null;
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                logger.WriteEntry("No local IP address provided - will use first non-localhost interface", EventLogEntryType.Warning);
            }
            expiredDirectory = (string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, EXPIRED_DIRECTORY_REGVAL, "");
            if (expiredDirectory.Length == 0)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                logger.WriteEntry("No expired message directory provided - administrative handling of unsent messages NOT available", EventLogEntryType.Warning);
            }
            sdsConnection = new SDSconnection();
            try
            {
                retryCheckPeriod = Int64.Parse((string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, RETRY_TIMER_PERIOD_REGVAL, ""));
            }
            catch { }

            string nulldefault = (string)Registry.GetValue(CONNECTION_MANAGER_REGSITRY_KEY, USE_NULL_DEFAULT_SYNCHRONOUS_HANDLER_REGVAL, "");
            if (nulldefault.ToLower().StartsWith("y"))
                defaultSynchronousResponseHandler = new NullSynchronousResponseHandler();
            else
                defaultSynchronousResponseHandler = new DefaultFileSaveSynchronousResponseHandler();
            defaultSpineHandler = new DefaultFileSaveSpineHandler();

            persistDurations = loadReceivedPersistDurations();
            if (retryCheckPeriod != 0)
                retryProcessorTimer = new Timer(processRetries, null, retryCheckPeriod, retryCheckPeriod);
        }