SshMessageFactoryTest.cs 35 KB

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