2
0

SshMessageFactoryTest.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.Linq;
  6. using Renci.SshNet.Common;
  7. using Renci.SshNet.Messages;
  8. using Renci.SshNet.Messages.Authentication;
  9. using Renci.SshNet.Messages.Connection;
  10. using Renci.SshNet.Messages.Transport;
  11. using Microsoft.VisualStudio.TestTools.UnitTesting;
  12. namespace Renci.SshNet.Tests
  13. {
  14. [TestClass]
  15. public class SshMessageFactoryTest
  16. {
  17. private SshMessageFactory _sshMessageFactory;
  18. private SshMessageFactoryOriginal _sshMessageFactoryOriginal;
  19. [TestInitialize]
  20. public void SetUp()
  21. {
  22. _sshMessageFactory = new SshMessageFactory();
  23. _sshMessageFactoryOriginal = new SshMessageFactoryOriginal();
  24. }
  25. [TestMethod]
  26. public void CreateShouldThrowSshExceptionWhenMessageIsNotEnabled()
  27. {
  28. const byte messageNumber = 60;
  29. try
  30. {
  31. _sshMessageFactory.Create(messageNumber);
  32. Assert.Fail();
  33. }
  34. catch (SshException ex)
  35. {
  36. Assert.IsNull(ex.InnerException);
  37. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
  38. }
  39. }
  40. [TestMethod]
  41. public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_OutsideOfMessageNumberRange()
  42. {
  43. const byte messageNumber = 255;
  44. try
  45. {
  46. _sshMessageFactory.Create(messageNumber);
  47. Assert.Fail();
  48. }
  49. catch (SshException ex)
  50. {
  51. Assert.IsNull(ex.InnerException);
  52. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message);
  53. }
  54. }
  55. [TestMethod]
  56. public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_WithinMessageNumberRange()
  57. {
  58. const byte messageNumber = 5;
  59. try
  60. {
  61. _sshMessageFactory.Create(messageNumber);
  62. Assert.Fail();
  63. }
  64. catch (SshException ex)
  65. {
  66. Assert.IsNull(ex.InnerException);
  67. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message);
  68. }
  69. }
  70. [TestMethod]
  71. public void CreateShouldThrowSshExceptionWhenMessageIsNotActivated()
  72. {
  73. const byte messageNumber = 60;
  74. const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ";
  75. _sshMessageFactory.EnableAndActivateMessage(messageName);
  76. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  77. try
  78. {
  79. _sshMessageFactory.Create(messageNumber);
  80. Assert.Fail();
  81. }
  82. catch (SshException ex)
  83. {
  84. Assert.IsNull(ex.InnerException);
  85. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
  86. }
  87. }
  88. [TestMethod]
  89. public void CreateShouldReturnMessageInstanceCorrespondingToMessageNumberWhenMessageIsEnabledAndActivated()
  90. {
  91. const byte messageNumber = 60;
  92. const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ";
  93. _sshMessageFactory.EnableAndActivateMessage(messageName);
  94. var actual = _sshMessageFactory.Create(messageNumber);
  95. Assert.IsNotNull(actual);
  96. Assert.AreEqual(typeof (PasswordChangeRequiredMessage), actual.GetType());
  97. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  98. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
  99. actual = _sshMessageFactory.Create(messageNumber);
  100. Assert.IsNotNull(actual);
  101. Assert.AreEqual(typeof(InformationRequestMessage), actual.GetType());
  102. }
  103. [TestMethod]
  104. public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsEnabled()
  105. {
  106. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  107. try
  108. {
  109. _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
  110. Assert.Fail();
  111. }
  112. catch (SshException ex)
  113. {
  114. Assert.IsNull(ex.InnerException);
  115. Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message);
  116. }
  117. // verify that the original message remains enabled
  118. var actual = _sshMessageFactory.Create(60);
  119. Assert.IsNotNull(actual);
  120. Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
  121. }
  122. [TestMethod]
  123. public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyDisabled()
  124. {
  125. const byte messageNumber = 60;
  126. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  127. _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  128. _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  129. // verify that message remains disabled
  130. try
  131. {
  132. _sshMessageFactory.Create(messageNumber);
  133. Assert.Fail();
  134. }
  135. catch (SshException ex)
  136. {
  137. Assert.IsNull(ex.InnerException);
  138. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
  139. }
  140. }
  141. [TestMethod]
  142. public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageWasNeverEnabled()
  143. {
  144. const byte messageNumber = 60;
  145. _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  146. // verify that message is disabled
  147. try
  148. {
  149. _sshMessageFactory.Create(messageNumber);
  150. Assert.Fail();
  151. }
  152. catch (SshException ex)
  153. {
  154. Assert.IsNull(ex.InnerException);
  155. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
  156. }
  157. }
  158. [TestMethod]
  159. public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported()
  160. {
  161. const string messageName = "WHATEVER";
  162. try
  163. {
  164. _sshMessageFactory.DisableAndDeactivateMessage("WHATEVER");
  165. Assert.Fail();
  166. }
  167. catch (SshException ex)
  168. {
  169. Assert.IsNull(ex.InnerException);
  170. Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message);
  171. }
  172. }
  173. [TestMethod]
  174. public void DisableAndDeactivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull()
  175. {
  176. const string messageName = null;
  177. try
  178. {
  179. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  180. Assert.Fail();
  181. }
  182. catch (ArgumentNullException ex)
  183. {
  184. Assert.IsNull(ex.InnerException);
  185. Assert.AreEqual("messageName", ex.ParamName);
  186. }
  187. }
  188. [TestMethod]
  189. public void EnableAndActivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsAlreadyEnabled()
  190. {
  191. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  192. try
  193. {
  194. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
  195. Assert.Fail();
  196. }
  197. catch (SshException ex)
  198. {
  199. Assert.IsNull(ex.InnerException);
  200. Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message);
  201. }
  202. // verify that the original message remains enabled
  203. var actual = _sshMessageFactory.Create(60);
  204. Assert.IsNotNull(actual);
  205. Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
  206. }
  207. [TestMethod]
  208. public void EnableAndActivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyEnabled()
  209. {
  210. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  211. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  212. var actual = _sshMessageFactory.Create(60);
  213. Assert.IsNotNull(actual);
  214. Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
  215. }
  216. [TestMethod]
  217. public void EnableAndActivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported()
  218. {
  219. const string messageName = "WHATEVER";
  220. try
  221. {
  222. _sshMessageFactory.EnableAndActivateMessage("WHATEVER");
  223. Assert.Fail();
  224. }
  225. catch (SshException ex)
  226. {
  227. Assert.IsNull(ex.InnerException);
  228. Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message);
  229. }
  230. }
  231. [TestMethod]
  232. public void EnableAndActivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull()
  233. {
  234. const string messageName = null;
  235. try
  236. {
  237. _sshMessageFactory.EnableAndActivateMessage(messageName);
  238. Assert.Fail();
  239. }
  240. catch (ArgumentNullException ex)
  241. {
  242. Assert.IsNull(ex.InnerException);
  243. Assert.AreEqual("messageName", ex.ParamName);
  244. }
  245. }
  246. [TestMethod]
  247. public void DisableNonKeyExchangeMessagesShouldDisableNonKeyExchangeMessages()
  248. {
  249. const byte messageNumber = 60;
  250. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  251. _sshMessageFactory.DisableNonKeyExchangeMessages();
  252. // verify that message is disabled
  253. try
  254. {
  255. _sshMessageFactory.Create(messageNumber);
  256. Assert.Fail();
  257. }
  258. catch (SshException ex)
  259. {
  260. Assert.IsNull(ex.InnerException);
  261. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
  262. }
  263. }
  264. [TestMethod]
  265. public void DisableNonKeyExchangeMessagesShouldNotDisableKeyExchangeMessages()
  266. {
  267. const byte messageNumber = 21;
  268. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_NEWKEYS");
  269. _sshMessageFactory.DisableNonKeyExchangeMessages();
  270. // verify that message remains enabled
  271. var actual = _sshMessageFactory.Create(messageNumber);
  272. Assert.IsNotNull(actual);
  273. Assert.AreEqual(typeof (NewKeysMessage), actual.GetType());
  274. }
  275. [TestMethod]
  276. public void EnableActivatedMessagesShouldEnableMessagesThatWereEnabledPriorToInvokingDisableNonKeyExchangeMessages()
  277. {
  278. const byte messageNumber = 60;
  279. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  280. _sshMessageFactory.DisableNonKeyExchangeMessages();
  281. _sshMessageFactory.EnableActivatedMessages();
  282. var actual = _sshMessageFactory.Create(messageNumber);
  283. Assert.IsNotNull(actual);
  284. Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
  285. }
  286. [TestMethod]
  287. public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledPriorToInvokingDisableNonKeyExchangeMessages()
  288. {
  289. const byte messageNumber = 60;
  290. _sshMessageFactory.DisableNonKeyExchangeMessages();
  291. _sshMessageFactory.EnableActivatedMessages();
  292. try
  293. {
  294. _sshMessageFactory.Create(messageNumber);
  295. Assert.Fail();
  296. }
  297. catch (SshException ex)
  298. {
  299. Assert.IsNull(ex.InnerException);
  300. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
  301. }
  302. }
  303. [TestMethod]
  304. public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledAfterInvokingDisableNonKeyExchangeMessages()
  305. {
  306. const byte messageNumber = 60;
  307. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  308. _sshMessageFactory.DisableNonKeyExchangeMessages();
  309. _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  310. _sshMessageFactory.EnableActivatedMessages();
  311. try
  312. {
  313. _sshMessageFactory.Create(messageNumber);
  314. Assert.Fail();
  315. }
  316. catch (SshException ex)
  317. {
  318. Assert.IsNull(ex.InnerException);
  319. Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
  320. }
  321. }
  322. [TestMethod]
  323. public void EnableActivatedMessagesShouldThrowSshExceptionWhenAnothersMessageWithSameMessageNumberWasEnabledAfterInvokingDisableNonKeyExchangeMessages()
  324. {
  325. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  326. _sshMessageFactory.DisableNonKeyExchangeMessages();
  327. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
  328. try
  329. {
  330. _sshMessageFactory.EnableActivatedMessages();
  331. Assert.Fail();
  332. }
  333. catch (SshException ex)
  334. {
  335. Assert.IsNull(ex.InnerException);
  336. Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_INFO_REQUEST'.", ex.Message);
  337. }
  338. }
  339. [TestMethod]
  340. public void EnableActivatedMessagesShouldLeaveMessagesEnabledThatWereEnabledAfterInvokingDisableNonKeyExchangeMessages()
  341. {
  342. const byte messageNumber = 60;
  343. _sshMessageFactory.DisableNonKeyExchangeMessages();
  344. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  345. _sshMessageFactory.EnableActivatedMessages();
  346. var actual = _sshMessageFactory.Create(messageNumber);
  347. Assert.IsNotNull(actual);
  348. Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
  349. }
  350. [TestMethod]
  351. public void HighestMessageNumberShouldCorrespondWithHighestSupportedMessageNumber()
  352. {
  353. var highestSupportMessageNumber = SshMessageFactory.AllMessages.Max(m => m.Number);
  354. Assert.AreEqual(highestSupportMessageNumber, SshMessageFactory.HighestMessageNumber);
  355. }
  356. [TestMethod]
  357. public void TotalMessageCountShouldBeTotalNumberOfSupportedMessages()
  358. {
  359. var totalNumberOfSupportedMessages = SshMessageFactory.AllMessages.Length;
  360. Assert.AreEqual(totalNumberOfSupportedMessages, SshMessageFactory.TotalMessageCount);
  361. }
  362. [TestMethod]
  363. [TestCategory("Performance")]
  364. public void Performance_Ctor()
  365. {
  366. const int runCount = 100000;
  367. // warm-up
  368. for (var i = 0; i < 3; i++)
  369. {
  370. var sshMessageFactory = new SshMessageFactory();
  371. var sshMessageFactoryOriginal = new SshMessageFactoryOriginal();
  372. }
  373. GC.Collect();
  374. GC.WaitForPendingFinalizers();
  375. GC.Collect();
  376. var stopwatch = new Stopwatch();
  377. stopwatch.Start();
  378. for (var i = 0; i < runCount; i++)
  379. {
  380. var sshMessageFactory = new SshMessageFactory();
  381. }
  382. GC.Collect();
  383. GC.WaitForPendingFinalizers();
  384. GC.Collect();
  385. stopwatch.Stop();
  386. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  387. stopwatch.Reset();
  388. stopwatch.Start();
  389. for (var i = 0; i < runCount; i++)
  390. {
  391. var sshMessageFactory = new SshMessageFactoryOriginal();
  392. }
  393. GC.Collect();
  394. GC.WaitForPendingFinalizers();
  395. GC.Collect();
  396. stopwatch.Stop();
  397. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  398. }
  399. [TestMethod]
  400. [TestCategory("LongRunning")]
  401. [TestCategory("Performance")]
  402. public void Performance_Create()
  403. {
  404. const int runCount = 10000000;
  405. const string messageName = "SSH_MSG_CHANNEL_CLOSE";
  406. _sshMessageFactory.EnableAndActivateMessage(messageName);
  407. _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
  408. // warm-up
  409. for (var i = 0; i < 3; i++)
  410. {
  411. _sshMessageFactory.Create(97);
  412. _sshMessageFactoryOriginal.Create(97);
  413. }
  414. GC.Collect();
  415. GC.WaitForPendingFinalizers();
  416. GC.Collect();
  417. var stopwatch = new Stopwatch();
  418. stopwatch.Start();
  419. for (var i = 0; i < runCount; i++)
  420. {
  421. var msg = _sshMessageFactory.Create(97);
  422. if (msg == null)
  423. Console.WriteLine();
  424. }
  425. GC.Collect();
  426. GC.WaitForPendingFinalizers();
  427. GC.Collect();
  428. stopwatch.Stop();
  429. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  430. stopwatch.Reset();
  431. stopwatch.Start();
  432. for (var i = 0; i < runCount; i++)
  433. {
  434. var msg = _sshMessageFactoryOriginal.Create(97);
  435. if (msg == null)
  436. Console.WriteLine();
  437. }
  438. GC.Collect();
  439. GC.WaitForPendingFinalizers();
  440. GC.Collect();
  441. stopwatch.Stop();
  442. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  443. }
  444. [TestMethod]
  445. [TestCategory("LongRunning")]
  446. [TestCategory("Performance")]
  447. public void Performance_EnableAndActivateMessage()
  448. {
  449. const int runCount = 1000000;
  450. const string messageName = "SSH_MSG_CHANNEL_CLOSE";
  451. // warm-up
  452. for (var i = 0; i < 3; i++)
  453. {
  454. _sshMessageFactory.EnableAndActivateMessage(messageName);
  455. _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
  456. }
  457. GC.Collect();
  458. GC.WaitForPendingFinalizers();
  459. GC.Collect();
  460. var stopwatch = new Stopwatch();
  461. stopwatch.Start();
  462. for (var i = 0; i < runCount; i++)
  463. _sshMessageFactory.EnableAndActivateMessage(messageName);
  464. GC.Collect();
  465. GC.WaitForPendingFinalizers();
  466. GC.Collect();
  467. stopwatch.Stop();
  468. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  469. stopwatch.Reset();
  470. stopwatch.Start();
  471. for (var i = 0; i < runCount; i++)
  472. _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
  473. GC.Collect();
  474. GC.WaitForPendingFinalizers();
  475. GC.Collect();
  476. stopwatch.Stop();
  477. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  478. }
  479. [TestMethod]
  480. [TestCategory("LongRunning")]
  481. [TestCategory("Performance")]
  482. public void Performance_DisableAndDeactivateMessage()
  483. {
  484. const int runCount = 1000000;
  485. const string messageName = "SSH_MSG_CHANNEL_CLOSE";
  486. // warm-up
  487. for (var i = 0; i < 3; i++)
  488. {
  489. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  490. _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
  491. }
  492. GC.Collect();
  493. GC.WaitForPendingFinalizers();
  494. GC.Collect();
  495. var stopwatch = new Stopwatch();
  496. stopwatch.Start();
  497. for (var i = 0; i < runCount; i++)
  498. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  499. GC.Collect();
  500. GC.WaitForPendingFinalizers();
  501. GC.Collect();
  502. stopwatch.Stop();
  503. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  504. stopwatch.Reset();
  505. stopwatch.Start();
  506. for (var i = 0; i < runCount; i++)
  507. _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
  508. GC.Collect();
  509. GC.WaitForPendingFinalizers();
  510. GC.Collect();
  511. stopwatch.Stop();
  512. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  513. }
  514. [TestMethod]
  515. [TestCategory("LongRunning")]
  516. [TestCategory("Performance")]
  517. public void Performance_DisableNonKeyExchangeMessages()
  518. {
  519. const int runCount = 1000000;
  520. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
  521. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_DEBUG");
  522. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
  523. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
  524. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
  525. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_DEBUG");
  526. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
  527. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
  528. // warm-up
  529. for (var i = 0; i < 3; i++)
  530. {
  531. _sshMessageFactory.DisableNonKeyExchangeMessages();
  532. _sshMessageFactory.EnableActivatedMessages();
  533. _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
  534. _sshMessageFactoryOriginal.EnableActivatedMessages();
  535. }
  536. //Console.WriteLine("Starting test");
  537. GC.Collect();
  538. GC.WaitForPendingFinalizers();
  539. GC.Collect();
  540. var stopwatch = new Stopwatch();
  541. stopwatch.Start();
  542. for (var i = 0; i < runCount; i++)
  543. {
  544. _sshMessageFactory.DisableNonKeyExchangeMessages();
  545. _sshMessageFactory.EnableActivatedMessages();
  546. }
  547. GC.Collect();
  548. GC.WaitForPendingFinalizers();
  549. GC.Collect();
  550. stopwatch.Stop();
  551. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  552. stopwatch.Reset();
  553. stopwatch.Start();
  554. for (var i = 0; i < runCount; i++)
  555. {
  556. _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
  557. _sshMessageFactoryOriginal.EnableActivatedMessages();
  558. }
  559. GC.Collect();
  560. GC.WaitForPendingFinalizers();
  561. GC.Collect();
  562. stopwatch.Stop();
  563. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  564. }
  565. internal class SshMessageFactoryOriginal
  566. {
  567. private readonly IEnumerable<MessageMetadata> _messagesMetadata;
  568. public SshMessageFactoryOriginal()
  569. {
  570. _messagesMetadata = new[]
  571. {
  572. new MessageMetadata {Name = "SSH_MSG_NEWKEYS", Number = 21, Type = typeof(NewKeysMessage)},
  573. new MessageMetadata
  574. {
  575. Name = "SSH_MSG_REQUEST_FAILURE",
  576. Number = 82,
  577. Type = typeof(RequestFailureMessage)
  578. },
  579. new MessageMetadata {Name = "SSH_MSG_KEXINIT", Number = 20, Type = typeof(KeyExchangeInitMessage)},
  580. new MessageMetadata
  581. {
  582. Name = "SSH_MSG_CHANNEL_OPEN_FAILURE",
  583. Number = 92,
  584. Type = typeof(ChannelOpenFailureMessage)
  585. },
  586. new MessageMetadata
  587. {
  588. Name = "SSH_MSG_CHANNEL_FAILURE",
  589. Number = 100,
  590. Type = typeof(ChannelFailureMessage)
  591. },
  592. new MessageMetadata
  593. {
  594. Name = "SSH_MSG_CHANNEL_EXTENDED_DATA",
  595. Number = 95,
  596. Type = typeof(ChannelExtendedDataMessage)
  597. },
  598. new MessageMetadata
  599. {
  600. Name = "SSH_MSG_CHANNEL_DATA",
  601. Number = 94,
  602. Type = typeof(ChannelDataMessage)
  603. },
  604. new MessageMetadata
  605. {
  606. Name = "SSH_MSG_USERAUTH_REQUEST",
  607. Number = 50,
  608. Type = typeof(RequestMessage)
  609. },
  610. new MessageMetadata
  611. {
  612. Name = "SSH_MSG_CHANNEL_REQUEST",
  613. Number = 98,
  614. Type = typeof(ChannelRequestMessage)
  615. },
  616. new MessageMetadata
  617. {
  618. Name = "SSH_MSG_USERAUTH_BANNER",
  619. Number = 53,
  620. Type = typeof(BannerMessage)
  621. },
  622. new MessageMetadata
  623. {
  624. Name = "SSH_MSG_USERAUTH_INFO_RESPONSE",
  625. Number = 61,
  626. Type = typeof(InformationResponseMessage)
  627. },
  628. new MessageMetadata
  629. {
  630. Name = "SSH_MSG_USERAUTH_FAILURE",
  631. Number = 51,
  632. Type = typeof(FailureMessage)
  633. },
  634. new MessageMetadata {Name = "SSH_MSG_DEBUG", Number = 4, Type = typeof(DebugMessage),},
  635. new MessageMetadata
  636. {
  637. Name = "SSH_MSG_KEXDH_INIT",
  638. Number = 30,
  639. Type = typeof(KeyExchangeDhInitMessage)
  640. },
  641. new MessageMetadata
  642. {
  643. Name = "SSH_MSG_GLOBAL_REQUEST",
  644. Number = 80,
  645. Type = typeof(GlobalRequestMessage)
  646. },
  647. new MessageMetadata
  648. {
  649. Name = "SSH_MSG_CHANNEL_OPEN",
  650. Number = 90,
  651. Type = typeof(ChannelOpenMessage)
  652. },
  653. new MessageMetadata
  654. {
  655. Name = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
  656. Number = 91,
  657. Type = typeof(ChannelOpenConfirmationMessage)
  658. },
  659. new MessageMetadata
  660. {
  661. Name = "SSH_MSG_USERAUTH_INFO_REQUEST",
  662. Number = 60,
  663. Type = typeof(InformationRequestMessage)
  664. },
  665. new MessageMetadata
  666. {
  667. Name = "SSH_MSG_UNIMPLEMENTED",
  668. Number = 3,
  669. Type = typeof(UnimplementedMessage)
  670. },
  671. new MessageMetadata
  672. {
  673. Name = "SSH_MSG_REQUEST_SUCCESS",
  674. Number = 81,
  675. Type = typeof(RequestSuccessMessage)
  676. },
  677. new MessageMetadata
  678. {
  679. Name = "SSH_MSG_CHANNEL_SUCCESS",
  680. Number = 99,
  681. Type = typeof(ChannelSuccessMessage)
  682. },
  683. new MessageMetadata
  684. {
  685. Name = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ",
  686. Number = 60,
  687. Type = typeof(PasswordChangeRequiredMessage)
  688. },
  689. new MessageMetadata {Name = "SSH_MSG_DISCONNECT", Number = 1, Type = typeof(DisconnectMessage)},
  690. new MessageMetadata
  691. {
  692. Name = "SSH_MSG_SERVICE_REQUEST",
  693. Number = 5,
  694. Type = typeof(ServiceRequestMessage)
  695. },
  696. new MessageMetadata
  697. {
  698. Name = "SSH_MSG_KEX_DH_GEX_REQUEST",
  699. Number = 34,
  700. Type = typeof(KeyExchangeDhGroupExchangeRequest)
  701. },
  702. new MessageMetadata
  703. {
  704. Name = "SSH_MSG_KEX_DH_GEX_GROUP",
  705. Number = 31,
  706. Type = typeof(KeyExchangeDhGroupExchangeGroup)
  707. },
  708. new MessageMetadata
  709. {
  710. Name = "SSH_MSG_USERAUTH_SUCCESS",
  711. Number = 52,
  712. Type = typeof(SuccessMessage)
  713. },
  714. new MessageMetadata
  715. {
  716. Name = "SSH_MSG_USERAUTH_PK_OK",
  717. Number = 60,
  718. Type = typeof(PublicKeyMessage)
  719. },
  720. new MessageMetadata {Name = "SSH_MSG_IGNORE", Number = 2, Type = typeof(IgnoreMessage)},
  721. new MessageMetadata
  722. {
  723. Name = "SSH_MSG_CHANNEL_WINDOW_ADJUST",
  724. Number = 93,
  725. Type = typeof(ChannelWindowAdjustMessage)
  726. },
  727. new MessageMetadata
  728. {
  729. Name = "SSH_MSG_CHANNEL_EOF",
  730. Number = 96,
  731. Type = typeof(ChannelEofMessage)
  732. },
  733. new MessageMetadata
  734. {
  735. Name = "SSH_MSG_CHANNEL_CLOSE",
  736. Number = 97,
  737. Type = typeof(ChannelCloseMessage)
  738. },
  739. new MessageMetadata
  740. {
  741. Name = "SSH_MSG_SERVICE_ACCEPT",
  742. Number = 6,
  743. Type = typeof(ServiceAcceptMessage)
  744. },
  745. new MessageMetadata
  746. {
  747. Name = "SSH_MSG_KEXDH_REPLY",
  748. Number = 31,
  749. Type = typeof(KeyExchangeDhReplyMessage)
  750. },
  751. new MessageMetadata
  752. {
  753. Name = "SSH_MSG_KEX_DH_GEX_INIT",
  754. Number = 32,
  755. Type = typeof(KeyExchangeDhGroupExchangeInit)
  756. },
  757. new MessageMetadata
  758. {
  759. Name = "SSH_MSG_KEX_DH_GEX_REPLY",
  760. Number = 33,
  761. Type = typeof(KeyExchangeDhGroupExchangeReply)
  762. }
  763. };
  764. }
  765. /// <summary>
  766. /// Disables and deactivate all messages.
  767. /// </summary>
  768. public void Reset()
  769. {
  770. foreach (var messageMetadata in _messagesMetadata)
  771. {
  772. messageMetadata.Activated = messageMetadata.Enabled = false;
  773. }
  774. }
  775. public void EnableActivatedMessages()
  776. {
  777. foreach (var messageMetadata in _messagesMetadata)
  778. {
  779. if (messageMetadata.Activated)
  780. messageMetadata.Enabled = true;
  781. }
  782. }
  783. public Message Create(byte messageNumber)
  784. {
  785. var messageMetadata =
  786. (from m in _messagesMetadata where m.Number == messageNumber && m.Enabled && m.Activated select m)
  787. .FirstOrDefault();
  788. if (messageMetadata == null)
  789. throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.",
  790. messageNumber));
  791. return messageMetadata.Type.CreateInstance<Message>();
  792. }
  793. public void DisableNonKeyExchangeMessages()
  794. {
  795. foreach (var messageMetadata in _messagesMetadata)
  796. {
  797. if (messageMetadata.Activated && messageMetadata.Number > 2 &&
  798. (messageMetadata.Number < 20 || messageMetadata.Number > 30))
  799. {
  800. //Console.WriteLine("Disabling " + messageMetadata.Name + "...");
  801. messageMetadata.Enabled = false;
  802. }
  803. }
  804. }
  805. public void EnableAndActivateMessage(string messageName)
  806. {
  807. lock (_messagesMetadata)
  808. {
  809. var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
  810. foreach (var messageMetadata in messagesMetadata)
  811. messageMetadata.Enabled = messageMetadata.Activated = true;
  812. }
  813. }
  814. public void DisableAndDeactivateMessage(string messageName)
  815. {
  816. lock (_messagesMetadata)
  817. {
  818. var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
  819. foreach (var messageMetadata in messagesMetadata)
  820. messageMetadata.Enabled = messageMetadata.Activated = false;
  821. }
  822. }
  823. private class MessageMetadata
  824. {
  825. public string Name { get; set; }
  826. public byte Number { get; set; }
  827. public bool Enabled { get; set; }
  828. public bool Activated { get; set; }
  829. public Type Type { get; set; }
  830. }
  831. }
  832. }
  833. }