Skip to content

Commit 60226be

Browse files
Merge pull request #418 from rabbitmq/rabbtimq-dotnet-client-417
Lock when writing to an SslStream
2 parents 2d3eff6 + c428e03 commit 60226be

File tree

4 files changed

+105
-58
lines changed

4 files changed

+105
-58
lines changed

projects/client/RabbitMQ.Client/src/client/impl/ModelBase.cs

Lines changed: 81 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public abstract class ModelBase : IFullModel, IRecoverable
7272
private readonly object m_eventLock = new object();
7373
private readonly object m_flowSendLock = new object();
7474
private readonly object m_shutdownLock = new object();
75+
private readonly object _rpcLock = new object();
7576

7677
private readonly SynchronizedList<ulong> m_unconfirmedSet = new SynchronizedList<ulong>();
7778

@@ -358,36 +359,43 @@ public string ConnectionOpen(string virtualHost,
358359
bool insist)
359360
{
360361
var k = new ConnectionOpenContinuation();
361-
Enqueue(k);
362-
try
363-
{
364-
_Private_ConnectionOpen(virtualHost, capabilities, insist);
365-
}
366-
catch (AlreadyClosedException)
362+
lock(_rpcLock)
367363
{
368-
// let continuation throw OperationInterruptedException,
369-
// which is a much more suitable exception before connection
370-
// negotiation finishes
364+
Enqueue(k);
365+
try
366+
{
367+
_Private_ConnectionOpen(virtualHost, capabilities, insist);
368+
}
369+
catch (AlreadyClosedException)
370+
{
371+
// let continuation throw OperationInterruptedException,
372+
// which is a much more suitable exception before connection
373+
// negotiation finishes
374+
}
375+
k.GetReply(HandshakeContinuationTimeout);
371376
}
372-
k.GetReply(HandshakeContinuationTimeout);
377+
373378
return k.m_knownHosts;
374379
}
375380

376381
public ConnectionSecureOrTune ConnectionSecureOk(byte[] response)
377382
{
378383
var k = new ConnectionStartRpcContinuation();
379-
Enqueue(k);
380-
try
384+
lock(_rpcLock)
381385
{
382-
_Private_ConnectionSecureOk(response);
383-
}
384-
catch (AlreadyClosedException)
385-
{
386-
// let continuation throw OperationInterruptedException,
387-
// which is a much more suitable exception before connection
388-
// negotiation finishes
386+
Enqueue(k);
387+
try
388+
{
389+
_Private_ConnectionSecureOk(response);
390+
}
391+
catch (AlreadyClosedException)
392+
{
393+
// let continuation throw OperationInterruptedException,
394+
// which is a much more suitable exception before connection
395+
// negotiation finishes
396+
}
397+
k.GetReply(HandshakeContinuationTimeout);
389398
}
390-
k.GetReply(HandshakeContinuationTimeout);
391399
return k.m_result;
392400
}
393401

@@ -397,19 +405,22 @@ public ConnectionSecureOrTune ConnectionStartOk(IDictionary<string, object> clie
397405
string locale)
398406
{
399407
var k = new ConnectionStartRpcContinuation();
400-
Enqueue(k);
401-
try
402-
{
403-
_Private_ConnectionStartOk(clientProperties, mechanism,
404-
response, locale);
405-
}
406-
catch (AlreadyClosedException)
408+
lock(_rpcLock)
407409
{
408-
// let continuation throw OperationInterruptedException,
409-
// which is a much more suitable exception before connection
410-
// negotiation finishes
410+
Enqueue(k);
411+
try
412+
{
413+
_Private_ConnectionStartOk(clientProperties, mechanism,
414+
response, locale);
415+
}
416+
catch (AlreadyClosedException)
417+
{
418+
// let continuation throw OperationInterruptedException,
419+
// which is a much more suitable exception before connection
420+
// negotiation finishes
421+
}
422+
k.GetReply(HandshakeContinuationTimeout);
411423
}
412-
k.GetReply(HandshakeContinuationTimeout);
413424
return k.m_result;
414425
}
415426

@@ -456,8 +467,11 @@ public void HandleCommand(ISession session, Command cmd)
456467
public MethodBase ModelRpc(MethodBase method, ContentHeaderBase header, byte[] body)
457468
{
458469
var k = new SimpleBlockingRpcContinuation();
459-
TransmitAndEnqueue(new Command(method, header, body), k);
460-
return k.GetReply(this.ContinuationTimeout).Method;
470+
lock(_rpcLock)
471+
{
472+
TransmitAndEnqueue(new Command(method, header, body), k);
473+
return k.GetReply(this.ContinuationTimeout).Method;
474+
}
461475
}
462476

463477
public void ModelSend(MethodBase method, ContentHeaderBase header, byte[] body)
@@ -1146,10 +1160,12 @@ public void BasicCancel(string consumerTag)
11461160
{
11471161
var k = new BasicConsumerRpcContinuation { m_consumerTag = consumerTag };
11481162

1149-
Enqueue(k);
1150-
1151-
_Private_BasicCancel(consumerTag, false);
1152-
k.GetReply(this.ContinuationTimeout);
1163+
lock(_rpcLock)
1164+
{
1165+
Enqueue(k);
1166+
_Private_BasicCancel(consumerTag, false);
1167+
k.GetReply(this.ContinuationTimeout);
1168+
}
11531169
lock (m_consumers)
11541170
{
11551171
m_consumers.Remove(consumerTag);
@@ -1180,12 +1196,15 @@ public string BasicConsume(string queue,
11801196

11811197
var k = new BasicConsumerRpcContinuation { m_consumer = consumer };
11821198

1183-
Enqueue(k);
1184-
// Non-nowait. We have an unconventional means of getting
1185-
// the RPC response, but a response is still expected.
1186-
_Private_BasicConsume(queue, consumerTag, noLocal, autoAck, exclusive,
1187-
/*nowait:*/ false, arguments);
1188-
k.GetReply(this.ContinuationTimeout);
1199+
lock(_rpcLock)
1200+
{
1201+
Enqueue(k);
1202+
// Non-nowait. We have an unconventional means of getting
1203+
// the RPC response, but a response is still expected.
1204+
_Private_BasicConsume(queue, consumerTag, noLocal, autoAck, exclusive,
1205+
/*nowait:*/ false, arguments);
1206+
k.GetReply(this.ContinuationTimeout);
1207+
}
11891208
string actualConsumerTag = k.m_consumerTag;
11901209

11911210
return actualConsumerTag;
@@ -1195,9 +1214,13 @@ public BasicGetResult BasicGet(string queue,
11951214
bool autoAck)
11961215
{
11971216
var k = new BasicGetRpcContinuation();
1198-
Enqueue(k);
1199-
_Private_BasicGet(queue, autoAck);
1200-
k.GetReply(this.ContinuationTimeout);
1217+
lock(_rpcLock)
1218+
{
1219+
Enqueue(k);
1220+
_Private_BasicGet(queue, autoAck);
1221+
k.GetReply(this.ContinuationTimeout);
1222+
}
1223+
12011224
return k.m_result;
12021225
}
12031226

@@ -1261,9 +1284,12 @@ public void BasicRecover(bool requeue)
12611284
{
12621285
var k = new SimpleBlockingRpcContinuation();
12631286

1264-
Enqueue(k);
1265-
_Private_BasicRecover(requeue);
1266-
k.GetReply(this.ContinuationTimeout);
1287+
lock(_rpcLock)
1288+
{
1289+
Enqueue(k);
1290+
_Private_BasicRecover(requeue);
1291+
k.GetReply(this.ContinuationTimeout);
1292+
}
12671293
}
12681294

12691295
public abstract void BasicRecoverAsync(bool requeue);
@@ -1559,9 +1585,12 @@ private QueueDeclareOk QueueDeclare(string queue, bool passive, bool durable, bo
15591585
bool autoDelete, IDictionary<string, object> arguments)
15601586
{
15611587
var k = new QueueDeclareRpcContinuation();
1562-
Enqueue(k);
1563-
_Private_QueueDeclare(queue, passive, durable, exclusive, autoDelete, false, arguments);
1564-
k.GetReply(this.ContinuationTimeout);
1588+
lock(_rpcLock)
1589+
{
1590+
Enqueue(k);
1591+
_Private_QueueDeclare(queue, passive, durable, exclusive, autoDelete, false, arguments);
1592+
k.GetReply(this.ContinuationTimeout);
1593+
}
15651594
return k.m_result;
15661595
}
15671596

projects/client/RabbitMQ.Client/src/client/impl/SocketFrameHandler.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ public class SocketFrameHandler : IFrameHandler
7777
private readonly ITcpClient m_socket;
7878
private readonly NetworkBinaryWriter m_writer;
7979
private readonly object _semaphore = new object();
80+
private readonly object _sslStreamLock = new object();
8081
private bool _closed;
82+
private bool _ssl = false;
8183
public SocketFrameHandler(AmqpTcpEndpoint endpoint,
8284
Func<AddressFamily, ITcpClient> socketFactory,
8385
int connectionTimeout, int readTimeout, int writeTimeout)
@@ -108,6 +110,7 @@ public SocketFrameHandler(AmqpTcpEndpoint endpoint,
108110
try
109111
{
110112
netstream = SslHelper.TcpUpgrade(netstream, endpoint.Ssl);
113+
_ssl = true;
111114
}
112115
catch (Exception)
113116
{
@@ -217,7 +220,7 @@ public void SendHeader()
217220
nbw.Write((byte)Endpoint.Protocol.MajorVersion);
218221
nbw.Write((byte)Endpoint.Protocol.MinorVersion);
219222
}
220-
m_writer.Write(ms.ToArray());
223+
Write(ms.ToArray());
221224
}
222225

223226
public void WriteFrame(OutboundFrame frame)
@@ -226,7 +229,7 @@ public void WriteFrame(OutboundFrame frame)
226229
var nbw = new NetworkBinaryWriter(ms);
227230
frame.WriteTo(nbw);
228231
m_socket.Client.Poll(m_writeableStateTimeout, SelectMode.SelectWrite);
229-
m_writer.Write(ms.ToArray());
232+
Write(ms.ToArray());
230233
}
231234

232235
public void WriteFrameSet(IList<OutboundFrame> frames)
@@ -235,7 +238,22 @@ public void WriteFrameSet(IList<OutboundFrame> frames)
235238
var nbw = new NetworkBinaryWriter(ms);
236239
foreach (var f in frames) f.WriteTo(nbw);
237240
m_socket.Client.Poll(m_writeableStateTimeout, SelectMode.SelectWrite);
238-
m_writer.Write(ms.ToArray());
241+
Write(ms.ToArray());
242+
}
243+
244+
private void Write(byte [] buffer)
245+
{
246+
if(_ssl)
247+
{
248+
lock (_sslStreamLock)
249+
{
250+
m_writer.Write(buffer);
251+
}
252+
}
253+
else
254+
{
255+
m_writer.Write(buffer);
256+
}
239257
}
240258

241259
private bool ShouldTryIPv6(AmqpTcpEndpoint endpoint)

projects/client/Unit/src/unit/TestExchangeDeclare.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class TestExchangeDeclare : IntegrationFixture {
5252

5353
[Test]
5454
[Category("RequireSMP")]
55-
public void TestConcurrentQueueDeclare()
55+
public void TestConcurrentExchangeDeclare()
5656
{
5757
string x = GenerateExchangeName();
5858
Random rnd = new Random();
@@ -83,7 +83,7 @@ public void TestConcurrentQueueDeclare()
8383
t.Join();
8484
}
8585

86-
Assert.IsNotNull(nse);
86+
Assert.IsNull(nse);
8787
Model.ExchangeDelete(x);
8888
}
8989
}

projects/client/Unit/src/unit/TestQueueDeclare.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public void TestConcurrentQueueDeclare()
8383
t.Join();
8484
}
8585

86-
Assert.IsNotNull(nse);
86+
Assert.IsNull(nse);
8787
Model.QueueDelete(q);
8888
}
8989
}

0 commit comments

Comments
 (0)