private async Task SendAsyncCore(ArraySegment<byte> buffer,
WebSocketMessageType messageType,
bool endOfMessage,
CancellationToken cancellationToken)
{
Debug.Assert(messageType == WebSocketMessageType.Binary || messageType == WebSocketMessageType.Text,
"'messageType' MUST be either 'WebSocketMessageType.Binary' or 'WebSocketMessageType.Text'.");
Debug.Assert(buffer != null);
string inputParameter = string.Empty;
if (NetEventSource.IsEnabled)
{
inputParameter = string.Format(CultureInfo.InvariantCulture,
"messageType: {0}, endOfMessage: {1}",
messageType,
endOfMessage);
NetEventSource.Enter(this, inputParameter);
}
try
{
ThrowIfPendingException();
ThrowIfDisposed();
ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived);
bool ownsCancellationTokenSource = false;
CancellationToken linkedCancellationToken = CancellationToken.None;
try
{
while (!(ownsCancellationTokenSource = _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken)))
{
Task keepAliveTask;
lock (SessionHandle)
{
keepAliveTask = _keepAliveTask;
if (keepAliveTask == null)
{
// Check whether there is still another outstanding send operation
// Potentially the keepAlive operation has completed before this thread
// was able to enter the SessionHandle-lock.
_sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource);
if (ownsCancellationTokenSource = _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken))
{
break;
}
else
{
throw new InvalidOperationException(
SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, nameof(SendAsync)));
}
}
}
await keepAliveTask.SuppressContextFlow();
ThrowIfPendingException();
_sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource);
}
if (NetEventSource.IsEnabled && buffer.Count > 0)
{
NetEventSource.DumpBuffer(this, buffer.Array, buffer.Offset, buffer.Count);
}
int position = buffer.Offset;
EnsureSendOperation();
_sendOperation.BufferType = GetBufferType(messageType, endOfMessage);
await _sendOperation.Process(buffer, linkedCancellationToken).SuppressContextFlow();
}
catch (Exception exception)
{
bool aborted = linkedCancellationToken.IsCancellationRequested;
Abort();
ThrowIfConvertibleException(nameof(SendAsync), exception, cancellationToken, aborted);
throw;
}
finally
{
_sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource);
}
}
finally
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Exit(this, inputParameter);
}
}
}