NTP Analyzer  0.8.2
Analyze the operation of time servers
Listener.cs
Go to the documentation of this file.
1 //
2 // Copyright (c) 2013-2017 Carsten Sonne Larsen <cs@innolan.net>
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 
22 using System;
23 using System.Globalization;
24 using System.Net;
25 using System.Net.Sockets;
26 using System.Text;
27 using System.Threading;
28 using Ntp.Common.Log;
29 
30 namespace Ntp.Analyzer.Monitor.Server
31 {
32  public sealed class Listener : IDisposable
33  {
40  public Listener(string ip, int port, LogBase log)
41  {
42  IPAddress address = IPAddress.Parse(ip);
43  endPoint = new IPEndPoint(address, port);
44  this.log = log;
45  shuttingDown = false;
46  }
47 
48  private readonly IPEndPoint endPoint;
49  private readonly LogBase log;
50  private Socket listenSocket;
51  private bool shuttingDown;
52 
56  public void Close()
57  {
58  shuttingDown = true;
59  listenSocket.Close();
60  }
61 
65  public void Open()
66  {
67  try
68  {
69  listenSocket = new Socket(
70  AddressFamily.InterNetwork,
71  SocketType.Stream,
72  ProtocolType.Tcp);
73 
74  listenSocket.Bind(endPoint);
75  listenSocket.Listen(3);
76 
77  listenSocket.BeginAccept(AcceptCallback, null);
78  }
79  catch (Exception ex)
80  {
81  log.WriteLine("Error while initializing listener " + ToString(), Severity.Error);
82  log.WriteLine(ex.Message, Severity.Debug);
83  log.WriteLine(ex, Severity.Trace);
84  }
85  }
86 
87  public override string ToString()
88  {
89  return endPoint.ToString();
90  }
91 
96  private void AcceptCallback(IAsyncResult asyncAccept)
97  {
98  try
99  {
100  Socket serverSocket = listenSocket.EndAccept(asyncAccept);
101 
102  if (serverSocket.Connected == false)
103  return;
104 
105  var req = new Request(128, serverSocket);
106 
107  serverSocket.BeginReceive(
108  req.Buffer,
109  0,
110  req.Buffer.Length,
111  SocketFlags.None,
112  ReceiveCallback,
113  req);
114  }
115  catch (Exception ex)
116  {
117  if (!shuttingDown)
118  {
119  log.WriteLine("Unexpected error in listener " + ToString(), Severity.Error);
120  log.WriteLine(ex.Message, Severity.Debug);
121  log.WriteLine(ex, Severity.Trace);
122  }
123  }
124  }
125 
130  private void ReceiveCallback(IAsyncResult asyncReceive)
131  {
132  try
133  {
134  var req = (Request) asyncReceive.AsyncState;
135  int size = req.Socket.EndReceive(asyncReceive);
136  req.ReSize(size);
137 
138  // Process request
139  Command command = CommandFactory.Create(req.Command, req.Arguments);
140 
141  // Force correct time format in strings, etc.
142  Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
143 
144  byte[] sendBuffer;
145 
146  if (command == null)
147  {
148  sendBuffer = Encoding.UTF8.GetBytes("Unknown command");
149  }
150  else
151  switch (command.CommandType)
152  {
153  case CommandType.Binary:
154  sendBuffer = (byte[]) command.Execute();
155  break;
156  case CommandType.Text:
157  var text = command.Execute() as string;
158  sendBuffer = text != null ? Encoding.UTF8.GetBytes(text) : new byte[] {0};
159  break;
160  default:
161  sendBuffer = Encoding.UTF8.GetBytes("Error in command module. Unknown command type.");
162  break;
163  }
164 
165  req.Socket.BeginSend(
166  sendBuffer,
167  0,
168  sendBuffer.Length,
169  SocketFlags.None,
170  SendCallback,
171  req.Socket);
172  }
173  catch (Exception ex)
174  {
175  log.WriteLine("Unexpected error in listener " + ToString(), Severity.Error);
176  log.WriteLine(ex.Message, Severity.Debug);
177  log.WriteLine(ex, Severity.Trace);
178  }
179  }
180 
185  private void SendCallback(IAsyncResult asyncSend)
186  {
187  try
188  {
189  var serverSocket = (Socket) asyncSend.AsyncState;
190  serverSocket.EndSend(asyncSend);
191  serverSocket.Shutdown(SocketShutdown.Both);
192  serverSocket.Close();
193 
194  // Start new worker socket.
195  listenSocket.BeginAccept(AcceptCallback, null);
196  }
197  catch (Exception ex)
198  {
199  log.WriteLine("Unexpected error in listener " + ToString(), Severity.Error);
200  log.WriteLine(ex.Message, Severity.Debug);
201  log.WriteLine(ex, Severity.Trace);
202  }
203  }
204 
205  #region IDisposable Support
206 
207  private bool disposedValue;
208 
209  private void Dispose(bool disposing)
210  {
211  if (disposedValue)
212  return;
213 
214  if (disposing && listenSocket != null)
215  {
216  if (listenSocket.Connected)
217  {
218  listenSocket.Shutdown(SocketShutdown.Both);
219  listenSocket.Close();
220  }
221 
222  listenSocket.Dispose();
223  listenSocket = null;
224  }
225 
226  disposedValue = true;
227  }
228 
230  {
231  Dispose(false);
232  }
233 
234  public void Dispose()
235  {
236  Dispose(true);
237  GC.SuppressFinalize(this);
238  }
239 
240  #endregion
241  }
242 }
void ReceiveCallback(IAsyncResult asyncReceive)
Receives the callback from client.
Definition: Listener.cs:130
void Open()
Open this listener.
Definition: Listener.cs:65
void SendCallback(IAsyncResult asyncSend)
Sends the callback response to client.
Definition: Listener.cs:185
abstract CommandType CommandType
Definition: Command.cs:26
Listener(string ip, int port, LogBase log)
Initializes a new instance of the Listener class.
Definition: Listener.cs:40
readonly IPEndPoint endPoint
Definition: Listener.cs:48
void AcceptCallback(IAsyncResult asyncAccept)
Accepts the callback from client.
Definition: Listener.cs:96
void Close()
Close this listener.
Definition: Listener.cs:56
void Dispose(bool disposing)
Definition: Listener.cs:209
static Command Create(string command, string[] args)