/* * Copyright (c) 2005-2006 Erik Tigerholm * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ namespace OpenTraffic.Network { using System; using System.Collections.Generic; using System.Net; using System.Security; using System.Threading; using System.Web.Services; using System.Xml.Serialization; using OpenTraffic.Model; using OpenTraffic.Model.Importer.Native; using OpenTraffic.Model.Result; using OpenTraffic.Model.Route; using OpenTraffic.Model.Simulator; using OpenTraffic.Model.SimulatorFactory; public enum PACKET_TYPES { ACK = -1, SYNC, PING }; [XmlType("CLIENT_TYPE")] public enum CLIENT_STATES { NONE, INITIALIZED, PRECALCULATION, SIMULATION, ROUTE_GENERATION, SYNC, RESTART, ABORTED } public enum CLIENT_SUBSTATES { START, RUNNING, ENDED, ABORTED } [WebService( Namespace = "http://www.opentraffic.net", Name = "OpenTraffic WebService", Description = "OpenTraffic WebService")] public class Client : MarshalByRefObject, IDisposable { public const int BROADCAST_PORT = 3266; public CLIENT_SUBSTATES substate { get; set; } public int PercentFinished { get { return (simulator != null) ? simulator.PercentFinished : 0; } } private CLIENT_STATES state; private TrafficProfile profile; private AbstractSimulatorFactory sf; private int id; private int sessionId; private TrafficModel model; private int WaitingClients; // Number of clients that it is waiting packets from. private int ConnectedClients; // Number of clients that the graphs connects to private ISimulator simulator; private List clients; private List newRoutes; private Dictionary routes; private Dictionary zones; private Dictionary classes; private List futureVehicles; private List futureLinkInfos; private int vehicleRecieved = 0; private int linkInfoRecieved = 0; private Dictionary hasRecievedPacket; private bool threaded; // private DateTime startCalculationTime; private UdpClient udpClient; private int alreadyRecievedClients; private int framesWithoutSync = 0; public Client() : this(6666, true) { } public Client(int port) : this(port, true) { } public Client(int port, bool threaded) { profile = new TrafficProfile(); this.state = CLIENT_STATES.NONE; udpClient = new UdpClient(port, new PacketFactory(), this); routes = new Dictionary(); zones = new Dictionary(); classes = new Dictionary(); futureVehicles = new List(); futureLinkInfos = new List(); hasRecievedPacket = new Dictionary(); alreadyRecievedClients = 0; this.threaded = threaded; if (threaded) { Console.WriteLine("Client Created " + port + ", udpClient=" + udpClient); Thread workerThread = new Thread(this.Work); workerThread.Start(); } } // [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)] [SecurityCritical] public override object InitializeLifetimeService() { return null; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { Console.WriteLine("Dispose(" + disposing + ")"); if (disposing) { if (udpClient != null) { udpClient.Dispose(); udpClient = null; } } } #region WebMethods [WebMethod] public bool IsOnline() { Console.WriteLine("Status?"); return true; } [WebMethod] public bool StartSimulation(int sessionId1) { // startCalculationTime = DateTime.Now; Console.WriteLine("Simulation started"); profile = new TrafficProfile(); if (this.sessionId != 0) return false; this.sessionId = sessionId1; state = CLIENT_STATES.INITIALIZED; return true; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "rs")] [WebMethod] public bool TransferModel( Model.TrafficModel m, List clients1, ResultData rs, int id1, IDictionary p, AbstractSimulatorFactory sf1) { this.id = id1; this.model = m; this.clients = clients1; this.sf = sf1; this.model.Partition = p; routes.Clear(); zones.Clear(); classes.Clear(); vehicleRecieved = 0; linkInfoRecieved = 0; foreach (RouteContainer r in m.Routes) { RouteContainer.NextId = Math.Max(r.Id + 1, RouteContainer.NextId); routes.Add(r.Id, r); } foreach (TrafficZone z in m.TrafficZones) { zones.Add(z.Id, z); } foreach (VehicleClass c in m.VehicleClasses) { classes.Add(c.IdRegister, c); } return true; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "bytes")] [WebMethod] public bool TransferModel( Byte[] bytes, List clients1, ResultData rs, int id1, IDictionary p, AbstractSimulatorFactory sf1) { TrafficModel m = NativeFileImporter.DeserializeRaw(bytes); return TransferModel(m, clients1, rs, id1, p, sf1); } [WebMethod] public void StartGenerateNewRoutes() { state = CLIENT_STATES.ROUTE_GENERATION; newRoutes = new List(); substate = CLIENT_SUBSTATES.RUNNING; } [WebMethod] public ResultData FetchResult() { if (model == null) return null; if (simulator.Result == null) return null; return simulator.Result; } [WebMethod] public bool StartRestartIteration() { substate = CLIENT_SUBSTATES.START; state = CLIENT_STATES.RESTART; substate = CLIENT_SUBSTATES.RUNNING; return true; } [WebMethod] public void SetHistoricalResult(ResultData res) { simulator.HistoricalResult = res; } [WebMethod] public void Abort() { sessionId = 0; Console.WriteLine("Abort..."); Console.WriteLine(udpClient + " li: " + linkInfoRecieved + " / vehs: " + vehicleRecieved); udpClient.Reset(); state = CLIENT_STATES.ABORTED; } [WebMethod] public void StartIteration() { state = CLIENT_STATES.SIMULATION; substate = CLIENT_SUBSTATES.RUNNING; } [WebMethod] public void StartPrecalculation() { state = CLIENT_STATES.PRECALCULATION; substate = CLIENT_SUBSTATES.RUNNING; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] [WebMethod] public List GetRoutesDescription() { List list = new List(); foreach (RouteContainer r in newRoutes) list.Add(new RouteDescription(r)); return list; } [WebMethod] public void AddRoutesDescription(List routes1) { if (routes1 != null) { Dictionary lookup = new Dictionary(); foreach (Model.TrafficModelLink l in model.TrafficModelLinks) lookup.Add(l.Id, l); foreach (Model.TrafficModelLink l in model.TrafficModelConnectors) lookup.Add(l.Id, l); foreach (Model.Route.RouteDescription rd in routes1) { RouteContainer r = rd.GetRoute(lookup); this.routes.Add(r.Id, r); } } } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] [WebMethod] public TrafficProfile GetProfile() { return profile; } [WebMethod] public void TransferTrash(Byte[] b) { if (b != null) { Console.WriteLine(b.Length); } } #endregion public void UpdateModel(IPEndPoint ip, List links, List vehicles) { if (links != null && vehicles != null) { vehicleRecieved += vehicles.Count; linkInfoRecieved += links.Count; // UGLY FAST HACK TO NOT PROCESS PACKET FROM OTHER ITERATION // If we receive packets from a client that has received a packet. just store it and add it in the beginning of next iteration // if (hasRecievedPacket[ip] == 0) { WaitingClients--; simulator.SyncronizeModel(vehicles, links); } else { printBelow("Double package", 2); alreadyRecievedClients++; foreach (Vehicle v in vehicles) futureVehicles.Add(v); foreach (LinkInfo l in links) futureLinkInfos.Add(l); } hasRecievedPacket[ip]++; } } private void PreCalculation() { state = CLIENT_STATES.PRECALCULATION; simulator = this.sf.Create(); simulator.Init(model, this.id); substate = CLIENT_SUBSTATES.ENDED; ConnectedClients = 0; hasRecievedPacket.Clear(); foreach (ClientDescription cd in clients) { if (simulator.ShouldSync(cd)) { ConnectedClients++; hasRecievedPacket.Add(cd.GetIPEndPoint(), 0); } } Console.Write(udpClient.port + ": Number of connected clients: " + ConnectedClients + " [ "); foreach (KeyValuePair kv in hasRecievedPacket) { Console.Write(kv.Key + ", "); } Console.WriteLine("]"); } private void RestartIteration() { simulator.RestartIteration(); udpClient.Reset(); futureLinkInfos.Clear(); futureVehicles.Clear(); foreach (ClientDescription cd in clients) { if (hasRecievedPacket.ContainsKey(cd.GetIPEndPoint())) { hasRecievedPacket[cd.GetIPEndPoint()] = 0; } } substate = CLIENT_SUBSTATES.ENDED; } private void Simulate() { if (!simulator.Iterate()) { substate = CLIENT_SUBSTATES.ENDED; return; } profile.Start("Syncronize"); foreach (ClientDescription cd in this.clients) { if (cd.id != id) { List vehicles = new List(); List links = new List(); if (simulator.GetSyncronizeVehicles(cd, vehicles, links)) udpClient.AddPacketToSend(new SyncPacket(this, udpClient, cd.GetIPEndPoint(), links, vehicles)); } } WaitingClients = ConnectedClients; profile.Start("Reset"); if (WaitingClients != 0) { simulator.SyncronizeModel(futureVehicles, futureLinkInfos); futureVehicles.Clear(); futureLinkInfos.Clear(); WaitingClients -= alreadyRecievedClients; alreadyRecievedClients = 0; state = CLIENT_STATES.SYNC; } } private static void printBelow(string str, int lines) { int l = Console.CursorLeft; int t = Console.CursorTop; for (int i = 0; i < lines; i++) Console.WriteLine(); Console.WriteLine(str); Console.CursorLeft = l; Console.CursorTop = t; } private void Syncronize() { while (true) { profile.Start("udpClient"); udpClient.go(); profile.Stop("udpClient"); framesWithoutSync++; if (framesWithoutSync == 10000) { printBelow(framesWithoutSync + ":" + this.id + " " + WaitingClients + " waiting sync. " + (udpClient.Ready ? "Ready" : "NotReady"), 1); } System.Diagnostics.Debug.Assert(WaitingClients >= 0); if (WaitingClients == 0 && udpClient.Ready) { framesWithoutSync = 0; state = CLIENT_STATES.SIMULATION; foreach (ClientDescription cd in this.clients) { if (hasRecievedPacket.ContainsKey(cd.GetIPEndPoint())) { hasRecievedPacket[cd.GetIPEndPoint()]--; System.Diagnostics.Debug.Assert(hasRecievedPacket[cd.GetIPEndPoint()] >= 0); } } return; } Thread.Sleep(0); } } private void GenerateNewRoutes() { newRoutes = simulator.GenerateMoreRoutes(); if (newRoutes.Count != 0) { int n = newRoutes[0].Id; int i = n - (n % clients.Count) + this.id; foreach (RouteContainer r in newRoutes) { i += clients.Count; r.Id = i; routes.Add(r.Id, r); } RouteContainer.NextId = i; } substate = CLIENT_SUBSTATES.ENDED; } public RouteContainer GetRoute(int id1) { return routes[id1]; } public TrafficZone GetZone(int id1) { return zones[id1]; } public VehicleClass GetClass(int id1) { return classes[id1]; } public void Work() { bool first = true; while (threaded || first) { if (substate == CLIENT_SUBSTATES.RUNNING) { switch (state) { case CLIENT_STATES.ROUTE_GENERATION: profile.Start("Routes"); GenerateNewRoutes(); profile.Stop("Routes"); break; case CLIENT_STATES.RESTART: profile.Start("Restart"); RestartIteration(); profile.Stop("Restart"); break; case CLIENT_STATES.PRECALCULATION: profile.Start("Precalculation"); PreCalculation(); profile.Stop("Precalculation"); break; case CLIENT_STATES.SIMULATION: profile.Start("Simulate"); Simulate(); profile.Stop("Simulate"); break; case CLIENT_STATES.SYNC: profile.Start("Syncronize"); Syncronize(); profile.Stop("Syncronize"); break; case CLIENT_STATES.ABORTED: state = CLIENT_STATES.NONE; break; default: Thread.Sleep(250); break; } } if (state == CLIENT_STATES.NONE) { // byte[] data = new byte[256]; udpClient.Ping(BROADCAST_PORT); Console.Write("."); Thread.Sleep(1000); } first = false; } } public void TestServer(IPEndPoint ipe, int count) { profile = new TrafficProfile(); for (int i = 0; i < count; i++) { udpClient.AddPacketToSend(new PingPacket(udpClient, ipe, 24)); while (!udpClient.Ready) { Thread.Sleep(0); udpClient.go(); } } Console.WriteLine(profile); } public void TestClient() { profile = new TrafficProfile(); while (true) { Thread.Sleep(0); udpClient.go(); } } public static void Test() { Client client = new Client(6665, false); try { Client server = new Client(6666, false); try { new Thread(client.TestClient).Start(); server.TestServer(new IPEndPoint(0x0100007f, 6666), 24 * 60 * 60 / 5 * 10); Console.WriteLine(client.udpClient); Console.WriteLine(server.udpClient); } finally { server.Dispose(); } } finally { client.Dispose(); } } private class PacketFactory : UdpClient.PacketFactory { public Packet CreatePacket(int t, Client obj, UdpClient n, IPEndPoint ip, int seq) { switch (t) { case (int)PACKET_TYPES.SYNC: return new SyncPacket(obj, n, ip); case (int)PACKET_TYPES.ACK: return new Network.AckPacket(n, ip, seq); case (int)PACKET_TYPES.PING: return new PingPacket(n, ip); } return null; } } } }