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;
        }