public void EndpointDispatcherAddTest7() { var uri = CreateAvailableUri("http://localhost:37564"); ServiceHost h = new ServiceHost(typeof(TestContract), uri); var binding = new BasicHttpBinding(); var listener = new MyChannelListener <IReplyChannel> (uri); MyChannelDispatcher d = new MyChannelDispatcher(listener); var ed = new EndpointDispatcher(new EndpointAddress(uri), "", ""); d.Endpoints.Add(ed); ed.DispatchRuntime.Type = typeof(TestContract); d.MessageVersion = MessageVersion.Default; // add service endpoint to open the host (unlike all tests above). h.AddServiceEndpoint(typeof(TestContract), new BasicHttpBinding(), uri.ToString()); h.ChannelDispatchers.Clear(); h.ChannelDispatchers.Add(d); d.Open(); // At this state, it does *not* call AcceptChannel() yet. // This rejects already-opened ChannelDispatcher. h.Open(TimeSpan.FromSeconds(10)); // should not reach here, but in case it didn't, it must be closed. h.Close(TimeSpan.FromSeconds(10)); }
// FIXME: this test itself indeed passes, but some weird conflict that blocks correspoding port happens between this and somewhere (probably above) // [Test] public void EndpointDispatcherAddTest9() // test singleton service { var uri = CreateAvailableUri("http://localhost:37564"); ServiceHost h = new ServiceHost(new TestContract(), uri); h.Description.Behaviors.Find <ServiceBehaviorAttribute> ().InstanceContextMode = InstanceContextMode.Single; var listener = new MyChannelListener <IReplyChannel> (uri); MyChannelDispatcher d = new MyChannelDispatcher(listener); var ed = new EndpointDispatcher(new EndpointAddress(uri), "", ""); d.Endpoints.Add(ed); ed.DispatchRuntime.Type = typeof(TestContract); d.MessageVersion = MessageVersion.Default; h.AddServiceEndpoint(typeof(TestContract), new BasicHttpBinding(), uri.ToString()); h.ChannelDispatchers.Clear(); Assert.IsNull(ed.DispatchRuntime.SingletonInstanceContext, "#1"); h.ChannelDispatchers.Add(d); Assert.IsNull(ed.DispatchRuntime.SingletonInstanceContext, "#2"); try { h.Open(TimeSpan.FromSeconds(10)); Assert.IsNull(ed.DispatchRuntime.InstanceProvider, "#4"); Assert.IsNotNull(ed.DispatchRuntime.InstanceContextProvider, "#5"); // it was set after ServiceHost.Open(). Assert.IsNotNull(ed.DispatchRuntime.SingletonInstanceContext, "#6"); } finally { h.Close(TimeSpan.FromSeconds(10)); h.Abort(); } }
public void EndpointDispatcherAddTest6() { var uri = CreateAvailableUri("http://localhost:37564"); ServiceHost h = new ServiceHost(typeof(TestContract), uri); var binding = new BasicHttpBinding(); var listener = new MyChannelListener <IReplyChannel> (uri); MyChannelDispatcher d = new MyChannelDispatcher(listener); var ed = new EndpointDispatcher(new EndpointAddress(uri), "", ""); d.Endpoints.Add(ed); Assert.IsFalse(d.Attached, "#x1"); ed.DispatchRuntime.Type = typeof(TestContract); d.MessageVersion = MessageVersion.Default; h.ChannelDispatchers.Add(d); Assert.IsTrue(d.Attached, "#x2"); d.Open(); // At this state, it does *not* call AcceptChannel() yet. Assert.IsFalse(listener.AcceptChannelTried, "#1"); Assert.IsFalse(listener.WaitForChannelTried, "#2"); Assert.IsNotNull(ed.DispatchRuntime, "#3"); Assert.IsNull(ed.DispatchRuntime.InstanceProvider, "#4"); Assert.IsNull(ed.DispatchRuntime.InstanceContextProvider, "#5"); // it is not still set after ChannelDispatcher.Open(). Assert.IsNull(ed.DispatchRuntime.InstanceProvider, "#5.2"); Assert.IsNull(ed.DispatchRuntime.SingletonInstanceContext, "#6"); d.Close(); // we don't have to even close it. }
[ExpectedException(typeof(InvalidOperationException))] // i.e. it is thrown synchronously in current thread. public void EndpointDispatcherAddTest4() { var uri = CreateAvailableUri("http://localhost:37564"); ServiceHost h = new ServiceHost(typeof(TestContract), uri); var listener = new MyChannelListener(uri); MyChannelDispatcher d = new MyChannelDispatcher(listener); var ed = new EndpointDispatcher(new EndpointAddress(uri), "", ""); Assert.IsNotNull(ed.DispatchRuntime, "#1"); Assert.IsNull(ed.DispatchRuntime.InstanceProvider, "#2"); Assert.IsNull(ed.DispatchRuntime.InstanceContextProvider, "#3"); Assert.IsNull(ed.DispatchRuntime.InstanceProvider, "#3.2"); Assert.IsNull(ed.DispatchRuntime.SingletonInstanceContext, "#4"); d.Endpoints.Add(ed); d.MessageVersion = MessageVersion.Default; h.ChannelDispatchers.Add(d); // it misses DispatchRuntime.Type, which seems set // automatically when the dispatcher is created in // ordinal process but need to be set manually in this case. try { d.Open(); try { // should not reach here, but in case it didn't, it must be closed. d.Close(TimeSpan.FromSeconds(10)); } catch { } } finally { Assert.AreEqual(CommunicationState.Opened, listener.State, "#5"); } }
// Validating duplicate listen URI causes this regression. // Since it is niche, I rather fixed ServiceHostBase to introduce validation. // It is probably because this code doesn't use ServiceEndpoint to build IChannelListener i.e. built without Binding. // We can add an extra field to ChannelDispatcher to indicate that it is from ServiceEndpoint (i.e. with Binding), // but it makes little sense especially for checking duplicate listen URIs. Duplicate listen URIs should be rejected anyways. public void EndpointDispatcherAddTest8() { var uri = CreateAvailableUri("http://localhost:37564"); ServiceHost h = new ServiceHost(typeof(TestContract), uri); var listener = new MyChannelListener <IReplyChannel> (uri); MyChannelDispatcher d = new MyChannelDispatcher(listener); var ed = new EndpointDispatcher(new EndpointAddress(uri), "", ""); d.Endpoints.Add(ed); ed.DispatchRuntime.Type = typeof(TestContract); d.MessageVersion = MessageVersion.Default; // add service endpoint to open the host (unlike all tests above). h.AddServiceEndpoint(typeof(TestContract), new BasicHttpBinding(), uri.ToString()); h.ChannelDispatchers.Clear(); h.ChannelDispatchers.Add(d); Assert.AreEqual(h, d.Host, "#0"); try { h.Open(TimeSpan.FromSeconds(10)); Assert.AreEqual(3, h.ChannelDispatchers.Count, "#0"); // TestContract, d, mex Assert.IsTrue(listener.BeginAcceptChannelTried, "#1"); // while it throws NIE ... Assert.IsFalse(listener.WaitForChannelTried, "#2"); Assert.IsNotNull(ed.DispatchRuntime, "#3"); Assert.IsNull(ed.DispatchRuntime.InstanceProvider, "#4"); Assert.IsNotNull(ed.DispatchRuntime.InstanceContextProvider, "#5"); // it was set after ServiceHost.Open(). Assert.IsNull(ed.DispatchRuntime.SingletonInstanceContext, "#6"); /* * var l = new HttpListener (); * l.Prefixes.Add (uri.ToString ()); * l.Start (); * l.Stop (); */ } finally { h.Close(TimeSpan.FromSeconds(10)); h.Abort(); } }
[ExpectedException(typeof(InvalidOperationException))] // i.e. it is thrown synchronously in current thread. public void EndpointDispatcherAddTest5() { var uri = CreateAvailableUri("http://localhost:37564"); ServiceHost h = new ServiceHost(typeof(TestContract), uri); var binding = new BasicHttpBinding(); var listener = new MyChannelListener(uri); MyChannelDispatcher d = new MyChannelDispatcher(listener); var ed = new EndpointDispatcher(new EndpointAddress(uri), "", ""); d.Endpoints.Add(ed); ed.DispatchRuntime.Type = typeof(TestContract); // different from Test4 d.MessageVersion = MessageVersion.Default; h.ChannelDispatchers.Add(d); // It rejects "unrecognized type" of the channel listener. // Test6 uses IChannelListener<IReplyChannel> and works. d.Open(); // should not reach here, but in case it didn't, it must be closed. d.Close(TimeSpan.FromSeconds(10)); }
static int Main(string[] args) { Log(DriverMessage); Log("Driver version " + DriverVersion); Log("Using opendnp3 version 3.1.1"); if (args.Length > 0) // first argument in number of the driver instance { int num; bool res = int.TryParse(args[0], out num); if (res) { ProtocolDriverInstanceNumber = num; } } if (args.Length > 1) // second argument is logLevel { int num; bool res = int.TryParse(args[1], out num); if (res) { LogLevel = num; } } string fname = JsonConfigFilePath; if (args.Length > 2) // third argument is config file name { if (File.Exists(args[2])) { fname = args[2]; } } if (!File.Exists(fname)) { fname = JsonConfigFilePathAlt; } if (!File.Exists(fname)) { Log("Missing config file " + JsonConfigFilePath); Environment.Exit(-1); } Log("Reading config file " + fname); string json = File.ReadAllText(fname); JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json); if ( JSConfig.mongoConnectionString == "" || JSConfig.mongoConnectionString == null ) { Log("Missing MongoDB connection string in JSON config file " + fname); Environment.Exit(-1); } if ( JSConfig.mongoDatabaseName == "" || JSConfig.mongoDatabaseName == null ) { Log("Missing MongoDB database name in JSON config file " + fname); Environment.Exit(-1); } Log("MongoDB database name: " + JSConfig.mongoDatabaseName); if (JSConfig.nodeName == "" || JSConfig.nodeName == null) { Log("Missing nodeName parameter in JSON config file " + fname); Environment.Exit(-1); } Log("Node name: " + JSConfig.nodeName); var Client = ConnectMongoClient(JSConfig); var DB = Client.GetDatabase(JSConfig.mongoDatabaseName); // read and process instances configuration var collinsts = DB .GetCollection <protocolDriverInstancesClass >(ProtocolDriverInstancesCollectionName); var instances = collinsts .Find(inst => inst.protocolDriver == ProtocolDriverName && inst.protocolDriverInstanceNumber == ProtocolDriverInstanceNumber && inst.enabled == true) .ToList(); var foundInstance = false; foreach (protocolDriverInstancesClass inst in instances) { if ( ProtocolDriverName == inst.protocolDriver && ProtocolDriverInstanceNumber == inst.protocolDriverInstanceNumber ) { foundInstance = true; if (!inst.enabled) { Log("Driver instance [" + ProtocolDriverInstanceNumber.ToString() + "] disabled!"); Environment.Exit(-1); } Log("Instance: " + inst.protocolDriverInstanceNumber.ToString()); var nodefound = false; foreach (var name in inst.nodeNames) { if (JSConfig.nodeName == name) { nodefound = true; } } if (!nodefound) { Log("Node '" + JSConfig.nodeName + "' not found in instances configuration!"); Environment.Exit(-1); } DriverInstance = inst; break; } break; // process just first result } if (!foundInstance) { Log("Driver instance [" + ProtocolDriverInstanceNumber + "] not found in configuration!"); Environment.Exit(-1); } // read and process connections configuration for this driver instance var collconns = DB .GetCollection <DNP3_connection>(ProtocolConnectionsCollectionName); var conns = collconns .Find(conn => conn.protocolDriver == ProtocolDriverName && conn.protocolDriverInstanceNumber == ProtocolDriverInstanceNumber && conn.enabled == true) .ToList(); foreach (DNP3_connection isrv in conns) { if (isrv.ipAddresses.Length < 1 && isrv.portName.Trim() == "") { Log("No ipAddresses or port name defined on conenction! " + isrv.name); Environment.Exit(-1); } DNP3conns.Add(isrv); Log(isrv.name.ToString() + " - New Connection"); } if (DNP3conns.Count == 0) { Log("No connections found!"); Environment.Exit(-1); } // start thread to process redundancy control Thread thrMongoRedundacy = new Thread(() => ProcessRedundancyMongo(JSConfig)); thrMongoRedundacy.Start(); // start thread to update acquired data to database Thread thrMongo = new Thread(() => ProcessMongo(JSConfig)); thrMongo.Start(); // start thread to watch for commands in the database using a change stream Thread thrMongoCmd = new Thread(() => ProcessMongoCmd(JSConfig)); thrMongoCmd.Start(); Log("Setting up connections & ASDU handlers..."); mgr = DNP3ManagerFactory.CreateManager(2 * Environment.ProcessorCount, new PrintingLogAdapter()); foreach (DNP3_connection srv in DNP3conns) { uint logLevel = LogLevels.NONE; if (LogLevel >= LogLevelBasic) { logLevel = LogLevels.NORMAL; } if (LogLevel >= LogLevelDetailed) { logLevel = LogLevels.NORMAL | LogLevels.APP_COMMS; } if (LogLevel >= LogLevelDebug) { logLevel = LogLevels.ALL; } MyChannelListener chlistener = new MyChannelListener(); chlistener.dnp3conn = srv; IChannel channel = null; // can be tcp, udp, tls, or serial if (srv.ipAddresses.Length > 0) // TCP, TLS or UDP { if (srv.ipAddressLocalBind.Trim() != "") { // UDP // look for the same channel config already created (multi-drop case) // if found, just reuse foreach (DNP3_connection conn in DNP3conns) { if (!(conn.channel is null)) { if (conn.ipAddressLocalBind.Trim() != "" && srv.ipAddressLocalBind.Trim() == conn.ipAddressLocalBind.Trim() && srv.ipAddresses[0] == conn.ipAddresses[0]) { channel = conn.channel; break; } } } if (!(channel is null)) { Log(srv.name + " - Reusing channel..."); } else { Log(srv.name + " - Creating UDP channel..."); ushort localUdpPort = 20000; string[] localIpAddrPort = srv.ipAddressLocalBind.Split(':'); if (localIpAddrPort.Length > 1) { if (int.TryParse(localIpAddrPort[1], out _)) { localUdpPort = System.Convert.ToUInt16(localIpAddrPort[1]); } } ushort remoteUdpPort = 20000; string[] remoteIpAddrPort = srv.ipAddresses[0].Split(':'); if (remoteIpAddrPort.Length > 1) { if (int.TryParse(remoteIpAddrPort[1], out _)) { remoteUdpPort = System.Convert.ToUInt16(remoteIpAddrPort[1]); } } channel = mgr.AddUDPChannel( "UDP:" + srv.name, logLevel, new ChannelRetry(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(5)), new IPEndpoint(localIpAddrPort[0], localUdpPort), new IPEndpoint(remoteIpAddrPort[0], remoteUdpPort), chlistener ); } } else { // TCP or TLS ushort tcpPort = 20000; string[] ipAddrPort = srv.ipAddresses[0].Split(':'); if (ipAddrPort.Length > 1) { if (int.TryParse(ipAddrPort[1], out _)) { tcpPort = System.Convert.ToUInt16(ipAddrPort[1]); } } // look for the same channel config already created (multi-drop case) // if found, just reuse foreach (DNP3_connection conn in DNP3conns) { if (!(conn.channel is null)) { if (srv.ipAddresses.SequenceEqual(conn.ipAddresses)) { channel = conn.channel; break; } } } if (!(channel is null)) { Log(srv.name + " - Reusing channel..."); }