SshMessageFactoryTest.cs 35 KB

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