source: trunk/CrypPlugins/KeySearcher/Server/Server.cs

Last change on this file was 8983, checked in by kopal, 7 months ago

Complete CrypTool 2 project

  • renamed "Cryptool" namespace to "CrypTool" namespace
File size: 8.9 KB
Line 
1using System;
2using System.Text;
3using System.Net.Sockets;
4using System.Threading;
5using System.Net;
6using System.Collections.Generic;
7
8class CrypToolServer
9{
10    #region Properties
11
12    public int Port {get;set;}
13
14    #endregion
15
16    #region Events
17
18    public delegate void JobCompletedDelegate(EndPoint ipep, JobResult j, String name);
19    public event JobCompletedDelegate OnJobCompleted;
20
21    public delegate bool ClientConnectedDelegate(EndPoint ipep, String name, String password);
22    public ClientConnectedDelegate OnClientAuth;
23
24    public delegate void EndPointDelegate(EndPoint ipep);
25    public event EndPointDelegate OnClientDisconnected;
26
27    public event EndPointDelegate OnClientRequestedJob;
28
29    public delegate void StringDelegate(String str);
30    public event StringDelegate OnErrorLog;
31   
32    #endregion
33
34    #region Variables
35
36    private Dictionary<EndPoint, TcpClient> connectedClients = new Dictionary<EndPoint, TcpClient>();
37    private TcpListener tcpListener;
38
39    enum State
40    {
41        Created,
42        Running,
43        Exiting,
44        Dead
45    }
46    private State state = State.Created;
47    #endregion
48
49    ///<summary>
50    /// Starts the server. Will block as long as the server runs, you might want to start this in an additional thread.
51    ///</summary>
52    public void Run()
53    {
54        if (OnJobCompleted == null ||
55            OnClientAuth == null ||
56            OnClientDisconnected == null ||
57            OnClientRequestedJob == null ||
58            OnErrorLog == null)
59        {
60            throw new Exception("One of the mandatory events was not bound");
61        }
62
63        try
64        {
65            lock (this)
66            {
67                if (state != State.Created)
68                {
69                    if (OnErrorLog != null)
70                    {
71                        OnErrorLog("Invalid state: " + state);
72                    }
73                    return;
74                }
75
76                // has to be in lock, otherwise a Stop call can cause an object
77                // disposed exception on tcpListener.start()
78                state = State.Running;
79                tcpListener = new TcpListener(IPAddress.Any, Port);
80                tcpListener.Start();
81            }
82
83
84            while (state == State.Running)
85            {
86                TcpClient client = tcpListener.AcceptTcpClient();
87                lock (connectedClients)
88                {
89                    connectedClients.Add(client.Client.RemoteEndPoint, client);
90                }
91                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
92                clientThread.Start(client);
93            }
94        }
95        catch (Exception e)
96        {
97            if (state == State.Running && OnErrorLog != null)
98            {
99                OnErrorLog("CrypToolServer: Got Exception while running "+e.Message);
100            }
101        }
102        finally
103        {
104            try
105            {
106                state = State.Dead;
107                tcpListener.Stop();
108            }
109            catch (Exception)
110            {
111            }
112            lock (connectedClients)
113            {
114                foreach (var client in connectedClients)
115                    client.Value.Close();
116            }
117        }
118    }
119   
120    public void SendJob(JobInput j, EndPoint i)
121    {
122        TcpClient client = null;
123        lock(connectedClients)
124        {
125            if (!connectedClients.TryGetValue(i, out client))
126            {
127                if (OnErrorLog != null)
128                    OnErrorLog("Tried to send job to not present external client " + i);
129                return;
130            }
131        }
132        try
133        {
134            lock (client)
135            {
136                var wrapped = new PlatformIndependentWrapper(client);
137
138                wrapped.WriteInt((int)ServerOpcodes.NEW_JOB);
139                wrapped.WriteString(j.Guid);
140                wrapped.WriteString(j.Src);
141                wrapped.WriteInt(j.Key.Length);
142                wrapped.WriteBytes(j.Key);
143                wrapped.WriteInt(j.LargerThen ? 1 : 0);
144                wrapped.WriteInt(j.Size);
145                wrapped.WriteInt(j.ResultSize);
146            }
147        }
148        catch (Exception e)
149        {
150            if (OnErrorLog != null)
151                OnErrorLog("Got " + e.GetType() + " while sending job to " + i);
152            client.Close();
153            // nothing more to do here. HandleClient will remove this from connectedClients
154        }
155    }
156
157    private void HandleClient(object obj)
158    {
159        var client = obj as TcpClient;
160        EndPoint ep = client.Client.RemoteEndPoint;
161
162        bool identified = false;
163        String name = string.Empty;
164        try
165        {
166            var wrapped = new PlatformIndependentWrapper(client);
167            while (true)
168            {
169                switch ((ClientOpcodes)wrapped.ReadInt())
170                {
171                    case ClientOpcodes.HELLO:
172                        {
173                            name = wrapped.ReadString();
174                            String password = wrapped.ReadString();
175                            if (OnClientAuth == null || !OnClientAuth(ep, name, password))
176                            {
177                                wrapped.WriteInt((int)ServerOpcodes.WRONG_PASSWORD);
178                                return;
179                            }
180                            identified = true;
181                        }
182                        break;
183
184                    case ClientOpcodes.JOB_RESULT:
185                        {
186                            if (!identified)
187                            {
188                                if (OnErrorLog != null)
189                                {
190                                    OnErrorLog("Client '" + ep + "' tried to post result without identification");
191                                }
192                                return;
193                            }
194
195                            var jobGuid = wrapped.ReadString();
196                            var resultList = new List<KeyValuePair<float, int>>();
197                            var resultListLength = wrapped.ReadInt();
198                            for (int c = 0; c < resultListLength; c++)
199                            {
200                                var key = wrapped.ReadInt();
201                                var cost = wrapped.ReadFloat();
202                                resultList.Add(new KeyValuePair<float, int>(cost, key));
203                            }
204
205                            JobResult rs = new JobResult();
206                            rs.Guid = jobGuid;
207                            rs.ResultList = resultList;
208
209                            if (OnJobCompleted != null)
210                            {
211                                OnJobCompleted(ep, rs, name);
212                            }
213                        }
214                        break;
215
216                    case ClientOpcodes.JOB_REQUEST:
217                        {
218                            if (!identified)
219                            {
220                                if (OnErrorLog != null)
221                                {
222                                    OnErrorLog("Client '" + ep + "' tried to request job without identification");
223                                }
224                                return;
225                            }
226
227                            if (OnClientRequestedJob != null)
228                            {
229                                OnClientRequestedJob(ep);
230                            }
231                        }
232                        break;
233                }
234            }
235        }
236        catch (SocketException)
237        {
238            // left blank intentionally. Will be thrown on client disconnect.
239        }
240        catch (Exception e)
241        {
242            if (OnErrorLog != null)
243            {
244                OnErrorLog("Client '" + ep + "' caused exception " + e);
245            }
246        }
247        finally
248        {
249            // just to be sure..
250            client.Close();
251
252            lock (connectedClients)
253            {
254                connectedClients.Remove(ep);
255            }
256
257            if (OnClientDisconnected != null)
258                OnClientDisconnected(ep);
259        }
260    }
261
262    /// <summary>
263    /// Closes this server. Any concurrent call to Run() in any other thread will return.
264    /// </summary>
265    public void Shutdown()
266    {
267        lock (this)
268        {
269            if (state == State.Dead ||
270                state == State.Exiting)
271            {
272                return;
273            }
274            state = State.Exiting;
275            try
276            {
277                tcpListener.Stop();
278            }
279            catch (Exception)
280            {
281            }
282        }
283    }
284}
Note: See TracBrowser for help on using the repository browser.