SshMessageFactoryTest.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  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. const byte messageNumber = 60;
  330. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  331. _sshMessageFactory.DisableNonKeyExchangeMessages();
  332. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
  333. try
  334. {
  335. _sshMessageFactory.EnableActivatedMessages();
  336. Assert.Fail();
  337. }
  338. catch (SshException ex)
  339. {
  340. Assert.IsNull(ex.InnerException);
  341. Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_INFO_REQUEST'.", ex.Message);
  342. }
  343. }
  344. [TestMethod]
  345. public void EnableActivatedMessagesShouldLeaveMessagesEnabledThatWereEnabledAfterInvokingDisableNonKeyExchangeMessages()
  346. {
  347. const byte messageNumber = 60;
  348. _sshMessageFactory.DisableNonKeyExchangeMessages();
  349. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  350. _sshMessageFactory.EnableActivatedMessages();
  351. var actual = _sshMessageFactory.Create(messageNumber);
  352. Assert.IsNotNull(actual);
  353. Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
  354. }
  355. [TestMethod]
  356. public void HighestMessageNumberShouldCorrespondWithHighestSupportedMessageNumber()
  357. {
  358. var highestSupportMessageNumber = SshMessageFactory.AllMessages.Max(m => m.Number);
  359. Assert.AreEqual(highestSupportMessageNumber, SshMessageFactory.HighestMessageNumber);
  360. }
  361. [TestMethod]
  362. public void TotalMessageCountShouldBeTotalNumberOfSupportedMessages()
  363. {
  364. var totalNumberOfSupportedMessages = SshMessageFactory.AllMessages.Length;
  365. Assert.AreEqual(totalNumberOfSupportedMessages, SshMessageFactory.TotalMessageCount);
  366. }
  367. [TestMethod]
  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. public void Performance_Create()
  405. {
  406. const int runCount = 10000000;
  407. const string messageName = "SSH_MSG_CHANNEL_CLOSE";
  408. _sshMessageFactory.EnableAndActivateMessage(messageName);
  409. _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
  410. // warm-up
  411. for (var i = 0; i < 3; i++)
  412. {
  413. _sshMessageFactory.Create(97);
  414. _sshMessageFactoryOriginal.Create(97);
  415. }
  416. GC.Collect();
  417. GC.WaitForPendingFinalizers();
  418. GC.Collect();
  419. var stopwatch = new Stopwatch();
  420. stopwatch.Start();
  421. for (var i = 0; i < runCount; i++)
  422. {
  423. var msg = _sshMessageFactory.Create(97);
  424. if (msg == null)
  425. Console.WriteLine();
  426. }
  427. GC.Collect();
  428. GC.WaitForPendingFinalizers();
  429. GC.Collect();
  430. stopwatch.Stop();
  431. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  432. stopwatch.Reset();
  433. stopwatch.Start();
  434. for (var i = 0; i < runCount; i++)
  435. {
  436. var msg = _sshMessageFactoryOriginal.Create(97);
  437. if (msg == null)
  438. Console.WriteLine();
  439. }
  440. GC.Collect();
  441. GC.WaitForPendingFinalizers();
  442. GC.Collect();
  443. stopwatch.Stop();
  444. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  445. }
  446. [TestMethod]
  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. public void Performance_DisableAndDeactivateMessage()
  481. {
  482. const int runCount = 1000000;
  483. const string messageName = "SSH_MSG_CHANNEL_CLOSE";
  484. // warm-up
  485. for (var i = 0; i < 3; i++)
  486. {
  487. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  488. _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
  489. }
  490. GC.Collect();
  491. GC.WaitForPendingFinalizers();
  492. GC.Collect();
  493. var stopwatch = new Stopwatch();
  494. stopwatch.Start();
  495. for (var i = 0; i < runCount; i++)
  496. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  497. GC.Collect();
  498. GC.WaitForPendingFinalizers();
  499. GC.Collect();
  500. stopwatch.Stop();
  501. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  502. stopwatch.Reset();
  503. stopwatch.Start();
  504. for (var i = 0; i < runCount; i++)
  505. _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
  506. GC.Collect();
  507. GC.WaitForPendingFinalizers();
  508. GC.Collect();
  509. stopwatch.Stop();
  510. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  511. }
  512. [TestMethod]
  513. public void Performance_DisableNonKeyExchangeMessages()
  514. {
  515. const int runCount = 1000000;
  516. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
  517. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_DEBUG");
  518. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
  519. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
  520. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
  521. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_DEBUG");
  522. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
  523. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
  524. // warm-up
  525. for (var i = 0; i < 3; i++)
  526. {
  527. _sshMessageFactory.DisableNonKeyExchangeMessages();
  528. _sshMessageFactory.EnableActivatedMessages();
  529. _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
  530. _sshMessageFactoryOriginal.EnableActivatedMessages();
  531. }
  532. //Console.WriteLine("Starting test");
  533. GC.Collect();
  534. GC.WaitForPendingFinalizers();
  535. GC.Collect();
  536. var stopwatch = new Stopwatch();
  537. stopwatch.Start();
  538. for (var i = 0; i < runCount; i++)
  539. {
  540. _sshMessageFactory.DisableNonKeyExchangeMessages();
  541. _sshMessageFactory.EnableActivatedMessages();
  542. }
  543. GC.Collect();
  544. GC.WaitForPendingFinalizers();
  545. GC.Collect();
  546. stopwatch.Stop();
  547. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  548. stopwatch.Reset();
  549. stopwatch.Start();
  550. for (var i = 0; i < runCount; i++)
  551. {
  552. _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
  553. _sshMessageFactoryOriginal.EnableActivatedMessages();
  554. }
  555. GC.Collect();
  556. GC.WaitForPendingFinalizers();
  557. GC.Collect();
  558. stopwatch.Stop();
  559. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  560. }
  561. internal class SshMessageFactoryOriginal
  562. {
  563. private readonly IEnumerable<MessageMetadata> _messagesMetadata;
  564. public SshMessageFactoryOriginal()
  565. {
  566. _messagesMetadata = new[]
  567. {
  568. new MessageMetadata {Name = "SSH_MSG_NEWKEYS", Number = 21, Type = typeof(NewKeysMessage)},
  569. new MessageMetadata
  570. {
  571. Name = "SSH_MSG_REQUEST_FAILURE",
  572. Number = 82,
  573. Type = typeof(RequestFailureMessage)
  574. },
  575. new MessageMetadata {Name = "SSH_MSG_KEXINIT", Number = 20, Type = typeof(KeyExchangeInitMessage)},
  576. new MessageMetadata
  577. {
  578. Name = "SSH_MSG_CHANNEL_OPEN_FAILURE",
  579. Number = 92,
  580. Type = typeof(ChannelOpenFailureMessage)
  581. },
  582. new MessageMetadata
  583. {
  584. Name = "SSH_MSG_CHANNEL_FAILURE",
  585. Number = 100,
  586. Type = typeof(ChannelFailureMessage)
  587. },
  588. new MessageMetadata
  589. {
  590. Name = "SSH_MSG_CHANNEL_EXTENDED_DATA",
  591. Number = 95,
  592. Type = typeof(ChannelExtendedDataMessage)
  593. },
  594. new MessageMetadata
  595. {
  596. Name = "SSH_MSG_CHANNEL_DATA",
  597. Number = 94,
  598. Type = typeof(ChannelDataMessage)
  599. },
  600. new MessageMetadata
  601. {
  602. Name = "SSH_MSG_USERAUTH_REQUEST",
  603. Number = 50,
  604. Type = typeof(RequestMessage)
  605. },
  606. new MessageMetadata
  607. {
  608. Name = "SSH_MSG_CHANNEL_REQUEST",
  609. Number = 98,
  610. Type = typeof(ChannelRequestMessage)
  611. },
  612. new MessageMetadata
  613. {
  614. Name = "SSH_MSG_USERAUTH_BANNER",
  615. Number = 53,
  616. Type = typeof(BannerMessage)
  617. },
  618. new MessageMetadata
  619. {
  620. Name = "SSH_MSG_USERAUTH_INFO_RESPONSE",
  621. Number = 61,
  622. Type = typeof(InformationResponseMessage)
  623. },
  624. new MessageMetadata
  625. {
  626. Name = "SSH_MSG_USERAUTH_FAILURE",
  627. Number = 51,
  628. Type = typeof(FailureMessage)
  629. },
  630. new MessageMetadata {Name = "SSH_MSG_DEBUG", Number = 4, Type = typeof(DebugMessage),},
  631. new MessageMetadata
  632. {
  633. Name = "SSH_MSG_KEXDH_INIT",
  634. Number = 30,
  635. Type = typeof(KeyExchangeDhInitMessage)
  636. },
  637. new MessageMetadata
  638. {
  639. Name = "SSH_MSG_GLOBAL_REQUEST",
  640. Number = 80,
  641. Type = typeof(GlobalRequestMessage)
  642. },
  643. new MessageMetadata
  644. {
  645. Name = "SSH_MSG_CHANNEL_OPEN",
  646. Number = 90,
  647. Type = typeof(ChannelOpenMessage)
  648. },
  649. new MessageMetadata
  650. {
  651. Name = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
  652. Number = 91,
  653. Type = typeof(ChannelOpenConfirmationMessage)
  654. },
  655. new MessageMetadata
  656. {
  657. Name = "SSH_MSG_USERAUTH_INFO_REQUEST",
  658. Number = 60,
  659. Type = typeof(InformationRequestMessage)
  660. },
  661. new MessageMetadata
  662. {
  663. Name = "SSH_MSG_UNIMPLEMENTED",
  664. Number = 3,
  665. Type = typeof(UnimplementedMessage)
  666. },
  667. new MessageMetadata
  668. {
  669. Name = "SSH_MSG_REQUEST_SUCCESS",
  670. Number = 81,
  671. Type = typeof(RequestSuccessMessage)
  672. },
  673. new MessageMetadata
  674. {
  675. Name = "SSH_MSG_CHANNEL_SUCCESS",
  676. Number = 99,
  677. Type = typeof(ChannelSuccessMessage)
  678. },
  679. new MessageMetadata
  680. {
  681. Name = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ",
  682. Number = 60,
  683. Type = typeof(PasswordChangeRequiredMessage)
  684. },
  685. new MessageMetadata {Name = "SSH_MSG_DISCONNECT", Number = 1, Type = typeof(DisconnectMessage)},
  686. new MessageMetadata
  687. {
  688. Name = "SSH_MSG_SERVICE_REQUEST",
  689. Number = 5,
  690. Type = typeof(ServiceRequestMessage)
  691. },
  692. new MessageMetadata
  693. {
  694. Name = "SSH_MSG_KEX_DH_GEX_REQUEST",
  695. Number = 34,
  696. Type = typeof(KeyExchangeDhGroupExchangeRequest)
  697. },
  698. new MessageMetadata
  699. {
  700. Name = "SSH_MSG_KEX_DH_GEX_GROUP",
  701. Number = 31,
  702. Type = typeof(KeyExchangeDhGroupExchangeGroup)
  703. },
  704. new MessageMetadata
  705. {
  706. Name = "SSH_MSG_USERAUTH_SUCCESS",
  707. Number = 52,
  708. Type = typeof(SuccessMessage)
  709. },
  710. new MessageMetadata
  711. {
  712. Name = "SSH_MSG_USERAUTH_PK_OK",
  713. Number = 60,
  714. Type = typeof(PublicKeyMessage)
  715. },
  716. new MessageMetadata {Name = "SSH_MSG_IGNORE", Number = 2, Type = typeof(IgnoreMessage)},
  717. new MessageMetadata
  718. {
  719. Name = "SSH_MSG_CHANNEL_WINDOW_ADJUST",
  720. Number = 93,
  721. Type = typeof(ChannelWindowAdjustMessage)
  722. },
  723. new MessageMetadata
  724. {
  725. Name = "SSH_MSG_CHANNEL_EOF",
  726. Number = 96,
  727. Type = typeof(ChannelEofMessage)
  728. },
  729. new MessageMetadata
  730. {
  731. Name = "SSH_MSG_CHANNEL_CLOSE",
  732. Number = 97,
  733. Type = typeof(ChannelCloseMessage)
  734. },
  735. new MessageMetadata
  736. {
  737. Name = "SSH_MSG_SERVICE_ACCEPT",
  738. Number = 6,
  739. Type = typeof(ServiceAcceptMessage)
  740. },
  741. new MessageMetadata
  742. {
  743. Name = "SSH_MSG_KEXDH_REPLY",
  744. Number = 31,
  745. Type = typeof(KeyExchangeDhReplyMessage)
  746. },
  747. new MessageMetadata
  748. {
  749. Name = "SSH_MSG_KEX_DH_GEX_INIT",
  750. Number = 32,
  751. Type = typeof(KeyExchangeDhGroupExchangeInit)
  752. },
  753. new MessageMetadata
  754. {
  755. Name = "SSH_MSG_KEX_DH_GEX_REPLY",
  756. Number = 33,
  757. Type = typeof(KeyExchangeDhGroupExchangeReply)
  758. }
  759. };
  760. }
  761. /// <summary>
  762. /// Disables and deactivate all messages.
  763. /// </summary>
  764. public void Reset()
  765. {
  766. foreach (var messageMetadata in _messagesMetadata)
  767. {
  768. messageMetadata.Activated = messageMetadata.Enabled = false;
  769. }
  770. }
  771. public void EnableActivatedMessages()
  772. {
  773. foreach (var messageMetadata in _messagesMetadata)
  774. {
  775. if (messageMetadata.Activated)
  776. messageMetadata.Enabled = true;
  777. }
  778. }
  779. public Message Create(byte messageNumber)
  780. {
  781. var messageMetadata =
  782. (from m in _messagesMetadata where m.Number == messageNumber && m.Enabled && m.Activated select m)
  783. .FirstOrDefault();
  784. if (messageMetadata == null)
  785. throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.",
  786. messageNumber));
  787. return messageMetadata.Type.CreateInstance<Message>();
  788. }
  789. public void DisableNonKeyExchangeMessages()
  790. {
  791. foreach (var messageMetadata in _messagesMetadata)
  792. {
  793. if (messageMetadata.Activated && messageMetadata.Number > 2 &&
  794. (messageMetadata.Number < 20 || messageMetadata.Number > 30))
  795. {
  796. //Console.WriteLine("Disabling " + messageMetadata.Name + "...");
  797. messageMetadata.Enabled = false;
  798. }
  799. }
  800. }
  801. public void EnableAndActivateMessage(string messageName)
  802. {
  803. lock (_messagesMetadata)
  804. {
  805. var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
  806. foreach (var messageMetadata in messagesMetadata)
  807. messageMetadata.Enabled = messageMetadata.Activated = true;
  808. }
  809. }
  810. public void DisableAndDeactivateMessage(string messageName)
  811. {
  812. lock (_messagesMetadata)
  813. {
  814. var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
  815. foreach (var messageMetadata in messagesMetadata)
  816. messageMetadata.Enabled = messageMetadata.Activated = false;
  817. }
  818. }
  819. private class MessageMetadata
  820. {
  821. public string Name { get; set; }
  822. public byte Number { get; set; }
  823. public bool Enabled { get; set; }
  824. public bool Activated { get; set; }
  825. public Type Type { get; set; }
  826. }
  827. }
  828. }
  829. }