Skip to content

Commit 3befefe

Browse files
committed
Handle ERR packet sent out of order. Fixes #662
1 parent 21aa9d2 commit 3befefe

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

src/MySqlConnector/Protocol/Serialization/ProtocolUtility.cs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.IO;
44
using System.Threading.Tasks;
55
using MySql.Data.MySqlClient;
6+
using MySqlConnector.Protocol.Payloads;
67
using MySqlConnector.Utilities;
78

89
namespace MySqlConnector.Protocol.Serialization
@@ -417,38 +418,45 @@ private static ValueTask<Packet> ReadPacketAfterHeader(ArraySegment<byte> header
417418
{
418419
if (headerBytes.Count < 4)
419420
{
420-
return protocolErrorBehavior == ProtocolErrorBehavior.Throw ?
421-
ValueTaskExtensions.FromException<Packet>(new EndOfStreamException("Expected to read 4 header bytes but only received {0}.".FormatInvariant(headerBytes.Count))) :
422-
default(ValueTask<Packet>);
421+
return protocolErrorBehavior == ProtocolErrorBehavior.Ignore ? default :
422+
ValueTaskExtensions.FromException<Packet>(new EndOfStreamException("Expected to read 4 header bytes but only received {0}.".FormatInvariant(headerBytes.Count)));
423423
}
424424

425425
var payloadLength = (int) SerializationUtility.ReadUInt32(headerBytes.Array, headerBytes.Offset, 3);
426426
int packetSequenceNumber = headerBytes.Array[headerBytes.Offset + 3];
427427

428+
Exception packetOutOfOrderException = null;
428429
var expectedSequenceNumber = getNextSequenceNumber() % 256;
429430
if (expectedSequenceNumber != -1 && packetSequenceNumber != expectedSequenceNumber)
430-
{
431-
if (protocolErrorBehavior == ProtocolErrorBehavior.Ignore)
432-
return default(ValueTask<Packet>);
433-
434-
var exception = MySqlProtocolException.CreateForPacketOutOfOrder(expectedSequenceNumber, packetSequenceNumber);
435-
return ValueTaskExtensions.FromException<Packet>(exception);
436-
}
431+
packetOutOfOrderException = MySqlProtocolException.CreateForPacketOutOfOrder(expectedSequenceNumber, packetSequenceNumber);
437432

438433
var payloadBytesTask = bufferedByteReader.ReadBytesAsync(byteHandler, payloadLength, ioBehavior);
439434
if (payloadBytesTask.IsCompleted)
440-
return CreatePacketFromPayload(payloadBytesTask.Result, payloadLength, protocolErrorBehavior);
441-
return AddContinuation(payloadBytesTask, payloadLength, protocolErrorBehavior);
435+
return CreatePacketFromPayload(payloadBytesTask.Result, payloadLength, protocolErrorBehavior, packetOutOfOrderException);
436+
return AddContinuation(payloadBytesTask, payloadLength, protocolErrorBehavior, packetOutOfOrderException);
442437

443438
// NOTE: use a local function (with no captures) to defer creation of lambda objects
444-
ValueTask<Packet> AddContinuation(ValueTask<ArraySegment<byte>> payloadBytesTask_, int payloadLength_, ProtocolErrorBehavior protocolErrorBehavior_)
445-
=> payloadBytesTask_.ContinueWith(x => CreatePacketFromPayload(x, payloadLength_, protocolErrorBehavior_));
439+
ValueTask<Packet> AddContinuation(ValueTask<ArraySegment<byte>> payloadBytesTask_, int payloadLength_, ProtocolErrorBehavior protocolErrorBehavior_, Exception packetOutOfOrderException_)
440+
=> payloadBytesTask_.ContinueWith(x => CreatePacketFromPayload(x, payloadLength_, protocolErrorBehavior_, packetOutOfOrderException_));
446441
}
447442

448-
private static ValueTask<Packet> CreatePacketFromPayload(ArraySegment<byte> payloadBytes, int payloadLength, ProtocolErrorBehavior protocolErrorBehavior) =>
449-
payloadBytes.Count >= payloadLength ? new ValueTask<Packet>(new Packet(payloadBytes)) :
443+
private static ValueTask<Packet> CreatePacketFromPayload(ArraySegment<byte> payloadBytes, int payloadLength, ProtocolErrorBehavior protocolErrorBehavior, Exception exception)
444+
{
445+
if (exception is object)
446+
{
447+
if (protocolErrorBehavior == ProtocolErrorBehavior.Ignore)
448+
return default;
449+
450+
if (payloadBytes.Count > 0 && payloadBytes.AsSpan()[0] == ErrorPayload.Signature)
451+
return new ValueTask<Packet>(new Packet(payloadBytes));
452+
453+
return ValueTaskExtensions.FromException<Packet>(exception);
454+
}
455+
456+
return payloadBytes.Count >= payloadLength ? new ValueTask<Packet>(new Packet(payloadBytes)) :
450457
protocolErrorBehavior == ProtocolErrorBehavior.Throw ? ValueTaskExtensions.FromException<Packet>(new EndOfStreamException("Expected to read {0} payload bytes but only received {1}.".FormatInvariant(payloadLength, payloadBytes.Count))) :
451-
default(ValueTask<Packet>);
458+
default;
459+
}
452460

453461
public static ValueTask<ArraySegment<byte>> ReadPayloadAsync(BufferedByteReader bufferedByteReader, IByteHandler byteHandler, Func<int> getNextSequenceNumber, ArraySegmentHolder<byte> cache, ProtocolErrorBehavior protocolErrorBehavior, IOBehavior ioBehavior)
454462
{

0 commit comments

Comments
 (0)