public async Task Ping(CancellationToken token) { var payload = Guid.NewGuid().ToByteArray(); var pongSource = new TaskCompletionSource <object>(); token.Register(() => pongSource.TrySetCanceled()); EventHandler <ControlFrameEventArgs> completionTrigger = (sender, e) => { if ((e.ControlFrame.FrameType == ControlFrame.Type.Pong) && payload.SequenceEqual(e.ControlFrame.Payload)) { pongSource.TrySetResult(null); } }; OnControlFrame += completionTrigger; await WebSocketProtocol.SendControlFrame(OutputStream, new ControlFrame { Payload = payload, FrameType = ControlFrame.Type.Ping, }); // either wait until they read it for us // or aquire the readlock and read it on our own var readLockAcquire = InputStream.ManualAcquire(); var pongTask = pongSource.Task; if (pongTask == await Task.WhenAny(readLockAcquire.Task, pongTask)) { System.Diagnostics.Debug.WriteLine("nice, they read it for us"); readLockAcquire.Cancel(); } else { System.Diagnostics.Debug.WriteLine("welp, our work"); using (var readLock = await readLockAcquire.Task) await WebSocketProtocol.ReadFrameGroupLockAcquired(readLock, HandleControlFrame, token, false); // pls tell me that this was the frame we needed if (!pongTask.IsCompleted) { throw new InvalidDataException("we pinged and they sent something else. welp."); } } OnControlFrame -= completionTrigger; }
private async Task HandleControlFrame(ControlFrame frame) { var eventargs = new ControlFrameEventArgs(frame); var controlFrameEvent = OnControlFrame; if (controlFrameEvent != null) { await Task.Factory.FromAsync(controlFrameEvent.BeginInvoke, controlFrameEvent.EndInvoke, this, eventargs, null); } if (!eventargs.SuppressAutoResponse && AutoPong && (frame.FrameType == ControlFrame.Type.Ping)) { await WebSocketProtocol.SendControlFrame(OutputStream, new ControlFrame { FrameType = ControlFrame.Type.Pong, Payload = frame.Payload }); } }
void IDisposable.Dispose() { WebSocketProtocol.SendControlFrame(OutputStream, new ControlFrame { FrameType = ControlFrame.Type.Close, }).Wait(); }