]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/lib/csharp/src/Transport/TSilverlightSocket.cs
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / lib / csharp / src / Transport / TSilverlightSocket.cs
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
21 * details.
22 */
23
24 /* only for silverlight */
25 #if SILVERLIGHT
26
27 using System;
28 using System.Net.Sockets;
29 using System.IO;
30 using System.Net;
31 using System.Threading;
32
33 namespace Thrift.Transport
34 {
35 public class TSilverlightSocket : TTransport
36 {
37 Socket socket = null;
38 static ManualResetEvent readAsyncComplete = new ManualResetEvent(false);
39 public event EventHandler<SocketAsyncEventArgs> connectHandler = null;
40
41 // memory stream for write cache.
42 private MemoryStream outputStream = new MemoryStream();
43
44 private string host = null;
45 private int port = 0;
46 private int timeout = 0;
47
48 // constructor
49 public TSilverlightSocket(string host, int port)
50 : this(host, port, 0)
51 {
52 }
53
54 // constructor
55 public TSilverlightSocket(string host, int port, int timeout)
56 {
57 this.host = host;
58 this.port = port;
59 this.timeout = timeout;
60
61 InitSocket();
62 }
63
64 private void InitSocket()
65 {
66 // Create a stream-based, TCP socket using the InterNetwork Address Family.
67 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
68 socket.NoDelay = true;
69 }
70
71 public int Timeout
72 {
73 set
74 {
75 timeout = value;
76 }
77 }
78
79 public string Host
80 {
81 get
82 {
83 return host;
84 }
85 }
86
87 public int Port
88 {
89 get
90 {
91 return port;
92 }
93 }
94
95 public override bool IsOpen
96 {
97 get
98 {
99 if (socket == null)
100 {
101 return false;
102 }
103
104 return socket.Connected;
105 }
106 }
107
108 public override void Open()
109 {
110 if (IsOpen)
111 {
112 throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
113 }
114
115 if (string.IsNullOrEmpty(host))
116 {
117 throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
118 }
119
120 if (port <= 0)
121 {
122 throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
123 }
124
125 if (socket == null)
126 {
127 InitSocket();
128 }
129
130 if (timeout == 0) // no timeout -> infinite
131 {
132 timeout = 10000; // set a default timeout for WP.
133 }
134
135 {
136 // Create DnsEndPoint. The hostName and port are passed in to this method.
137 DnsEndPoint hostEntry = new DnsEndPoint(this.host, this.port);
138
139 // Create a SocketAsyncEventArgs object to be used in the connection request
140 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
141 socketEventArg.RemoteEndPoint = hostEntry;
142
143 // Inline event handler for the Completed event.
144 // Note: This event handler was implemented inline in order to make this method self-contained.
145 socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
146 {
147 if (connectHandler != null)
148 {
149 connectHandler(this, e);
150 }
151 });
152
153 // Make an asynchronous Connect request over the socket
154 socket.ConnectAsync(socketEventArg);
155 }
156 }
157
158 public override int Read(byte[] buf, int off, int len)
159 {
160 bool _timeout = true;
161 string _error = null;
162 int _recvBytes = -1;
163
164 if (socket == null)
165 {
166 throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Socket is not open");
167 }
168
169 // Create SocketAsyncEventArgs context object
170 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
171 socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
172
173 // Setup the buffer to receive the data
174 socketEventArg.SetBuffer(buf, off, len);
175
176 // Inline event handler for the Completed event.
177 // Note: This even handler was implemented inline in order to make
178 // this method self-contained.
179 socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
180 {
181 _timeout = false;
182
183 if (e.SocketError == SocketError.Success)
184 {
185 _recvBytes = e.BytesTransferred;
186 }
187 else
188 {
189 _error = e.SocketError.ToString();
190 }
191
192 readAsyncComplete.Set();
193 });
194
195 // Sets the state of the event to nonsignaled, causing threads to block
196 readAsyncComplete.Reset();
197
198 // Make an asynchronous Receive request over the socket
199 socket.ReceiveAsync(socketEventArg);
200
201 // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
202 // If no response comes back within this time then proceed
203 readAsyncComplete.WaitOne(this.timeout);
204
205 if (_timeout)
206 {
207 throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Socket recv timeout");
208 }
209
210 if (_error != null)
211 {
212 throw new TTransportException(TTransportException.ExceptionType.Unknown, _error);
213 }
214
215 return _recvBytes;
216 }
217
218 public override void Write(byte[] buf, int off, int len)
219 {
220 outputStream.Write(buf, off, len);
221 }
222
223 private void beginFlush_Completed(object sender, SocketAsyncEventArgs e)
224 {
225 FlushAsyncResult flushAsyncResult = e.UserToken as FlushAsyncResult;
226 flushAsyncResult.UpdateStatusToComplete();
227 flushAsyncResult.NotifyCallbackWhenAvailable();
228
229 if (e.SocketError != SocketError.Success)
230 {
231 throw new TTransportException(TTransportException.ExceptionType.Unknown, e.SocketError.ToString());
232 }
233 }
234
235 public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
236 {
237 // Extract request and reset buffer
238 byte[] data = outputStream.ToArray();
239
240 FlushAsyncResult flushAsyncResult = new FlushAsyncResult(callback, state);
241
242 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
243 socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
244 socketEventArg.UserToken = flushAsyncResult;
245
246 socketEventArg.Completed += beginFlush_Completed;
247 socketEventArg.SetBuffer(data, 0, data.Length);
248
249 socket.SendAsync(socketEventArg);
250
251 return flushAsyncResult;
252 }
253
254 public override void EndFlush(IAsyncResult asyncResult)
255 {
256 try
257 {
258 var flushAsyncResult = (FlushAsyncResult)asyncResult;
259
260 if (!flushAsyncResult.IsCompleted)
261 {
262 var waitHandle = flushAsyncResult.AsyncWaitHandle;
263 waitHandle.WaitOne();
264 waitHandle.Close();
265 }
266
267 if (flushAsyncResult.AsyncException != null)
268 {
269 throw flushAsyncResult.AsyncException;
270 }
271 }
272 finally
273 {
274 outputStream = new MemoryStream();
275 }
276 }
277
278 // Copy from impl from THttpClient.cs
279 // Based on http://msmvps.com/blogs/luisabreu/archive/2009/06/15/multithreading-implementing-the-iasyncresult-interface.aspx
280 class FlushAsyncResult : IAsyncResult
281 {
282 private volatile Boolean _isCompleted;
283 private ManualResetEvent _evt;
284 private readonly AsyncCallback _cbMethod;
285 private readonly object _state;
286
287 public FlushAsyncResult(AsyncCallback cbMethod, object state)
288 {
289 _cbMethod = cbMethod;
290 _state = state;
291 }
292
293 internal byte[] Data { get; set; }
294 internal Socket Connection { get; set; }
295 internal TTransportException AsyncException { get; set; }
296
297 public object AsyncState
298 {
299 get { return _state; }
300 }
301
302 public WaitHandle AsyncWaitHandle
303 {
304 get { return GetEvtHandle(); }
305 }
306
307 public bool CompletedSynchronously
308 {
309 get { return false; }
310 }
311
312 public bool IsCompleted
313 {
314 get { return _isCompleted; }
315 }
316
317 private readonly object _locker = new object();
318
319 private ManualResetEvent GetEvtHandle()
320 {
321 lock (_locker)
322 {
323 if (_evt == null)
324 {
325 _evt = new ManualResetEvent(false);
326 }
327 if (_isCompleted)
328 {
329 _evt.Set();
330 }
331 }
332 return _evt;
333 }
334
335 internal void UpdateStatusToComplete()
336 {
337 _isCompleted = true; //1. set _iscompleted to true
338 lock (_locker)
339 {
340 if (_evt != null)
341 {
342 _evt.Set(); //2. set the event, when it exists
343 }
344 }
345 }
346
347 internal void NotifyCallbackWhenAvailable()
348 {
349 if (_cbMethod != null)
350 {
351 _cbMethod(this);
352 }
353 }
354 }
355
356 public override void Close()
357 {
358 if (socket != null)
359 {
360 socket.Close();
361 socket = null;
362 }
363 }
364
365 #region " IDisposable Support "
366 private bool _IsDisposed;
367
368 // IDisposable
369 protected override void Dispose(bool disposing)
370 {
371 if (!_IsDisposed)
372 {
373 if (disposing)
374 {
375 if (outputStream != null)
376 {
377 outputStream.Dispose();
378 }
379 outputStream = null;
380 if (socket != null)
381 {
382 ((IDisposable)socket).Dispose();
383 }
384 }
385 }
386 _IsDisposed = true;
387 }
388 #endregion
389 }
390 }
391
392
393 #endif