SshMessageFactoryTest.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. #if SILVERLIGHT
  2. using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
  3. #else
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Globalization;
  8. using System.Linq;
  9. using Microsoft.VisualStudio.TestTools.UnitTesting;
  10. using Renci.SshNet.Common;
  11. using Renci.SshNet.Messages;
  12. using Renci.SshNet.Messages.Authentication;
  13. using Renci.SshNet.Messages.Connection;
  14. using Renci.SshNet.Messages.Transport;
  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 EnableInformationRequestMessage()
  31. {
  32. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
  33. var message = _sshMessageFactory.Create(60);
  34. Assert.AreEqual(typeof(InformationRequestMessage), message.GetType());
  35. }
  36. [TestMethod]
  37. public void EnablePasswordChangeRequiredMessage()
  38. {
  39. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  40. var message = _sshMessageFactory.Create(60);
  41. Assert.AreEqual(typeof(PasswordChangeRequiredMessage), message.GetType());
  42. }
  43. [TestMethod]
  44. public void Di()
  45. {
  46. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
  47. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
  48. _sshMessageFactory.DisableNonKeyExchangeMessages();
  49. try
  50. {
  51. _sshMessageFactory.Create(6); // SSH_MSG_SERVICE_ACCEPT
  52. Assert.Fail();
  53. }
  54. catch (SshException)
  55. {
  56. }
  57. try
  58. {
  59. _sshMessageFactory.Create(60);
  60. // SSH_MSG_USERAUTH_PASSWD_CHANGEREQ or SSH_MSG_USERAUTH_INFO_REQUEST or SSH_MSG_USERAUTH_PK_OK
  61. Assert.Fail();
  62. }
  63. catch (SshException)
  64. {
  65. }
  66. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
  67. var message = _sshMessageFactory.Create(60);
  68. Assert.AreEqual(typeof(InformationRequestMessage), message.GetType());
  69. _sshMessageFactory.EnableActivatedMessages();
  70. var message2 = _sshMessageFactory.Create(60);
  71. Assert.AreEqual(typeof(InformationRequestMessage), message2.GetType());
  72. }
  73. [TestMethod]
  74. public void Performance_Ctor()
  75. {
  76. const int runCount = 100000;
  77. // warm-up
  78. for (var i = 0; i < 3; i++)
  79. {
  80. var sshMessageFactory = new SshMessageFactory();
  81. var sshMessageFactoryOriginal = new SshMessageFactoryOriginal();
  82. }
  83. GC.Collect();
  84. GC.WaitForPendingFinalizers();
  85. GC.Collect();
  86. var stopwatch = new Stopwatch();
  87. stopwatch.Start();
  88. for (var i = 0; i < runCount; i++)
  89. {
  90. var sshMessageFactory = new SshMessageFactory();
  91. }
  92. GC.Collect();
  93. GC.WaitForPendingFinalizers();
  94. GC.Collect();
  95. stopwatch.Stop();
  96. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  97. stopwatch.Reset();
  98. stopwatch.Start();
  99. for (var i = 0; i < runCount; i++)
  100. {
  101. var sshMessageFactory = new SshMessageFactoryOriginal();
  102. }
  103. GC.Collect();
  104. GC.WaitForPendingFinalizers();
  105. GC.Collect();
  106. stopwatch.Stop();
  107. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  108. }
  109. [TestMethod]
  110. public void Performance_Create()
  111. {
  112. const int runCount = 10000000;
  113. const string messageName = "SSH_MSG_CHANNEL_CLOSE";
  114. _sshMessageFactory.EnableAndActivateMessage(messageName);
  115. _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
  116. // warm-up
  117. for (var i = 0; i < 3; i++)
  118. {
  119. _sshMessageFactory.Create(97);
  120. _sshMessageFactoryOriginal.Create(97);
  121. }
  122. GC.Collect();
  123. GC.WaitForPendingFinalizers();
  124. GC.Collect();
  125. var stopwatch = new Stopwatch();
  126. stopwatch.Start();
  127. for (var i = 0; i < runCount; i++)
  128. {
  129. var msg = _sshMessageFactory.Create(97);
  130. if (msg == null)
  131. Console.WriteLine();
  132. }
  133. GC.Collect();
  134. GC.WaitForPendingFinalizers();
  135. GC.Collect();
  136. stopwatch.Stop();
  137. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  138. stopwatch.Reset();
  139. stopwatch.Start();
  140. for (var i = 0; i < runCount; i++)
  141. {
  142. var msg = _sshMessageFactoryOriginal.Create(97);
  143. if (msg == null)
  144. Console.WriteLine();
  145. }
  146. GC.Collect();
  147. GC.WaitForPendingFinalizers();
  148. GC.Collect();
  149. stopwatch.Stop();
  150. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  151. }
  152. [TestMethod]
  153. public void Performance_EnableAndActivateMessage()
  154. {
  155. const int runCount = 1000000;
  156. const string messageName = "SSH_MSG_CHANNEL_CLOSE";
  157. // warm-up
  158. for (var i = 0; i < 3; i++)
  159. {
  160. _sshMessageFactory.EnableAndActivateMessage(messageName);
  161. _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
  162. }
  163. GC.Collect();
  164. GC.WaitForPendingFinalizers();
  165. GC.Collect();
  166. var stopwatch = new Stopwatch();
  167. stopwatch.Start();
  168. for (var i = 0; i < runCount; i++)
  169. _sshMessageFactory.EnableAndActivateMessage(messageName);
  170. GC.Collect();
  171. GC.WaitForPendingFinalizers();
  172. GC.Collect();
  173. stopwatch.Stop();
  174. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  175. stopwatch.Reset();
  176. stopwatch.Start();
  177. for (var i = 0; i < runCount; i++)
  178. _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
  179. GC.Collect();
  180. GC.WaitForPendingFinalizers();
  181. GC.Collect();
  182. stopwatch.Stop();
  183. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  184. }
  185. [TestMethod]
  186. public void Performance_DisableAndDeactivateMessage()
  187. {
  188. const int runCount = 1000000;
  189. const string messageName = "SSH_MSG_CHANNEL_CLOSE";
  190. // warm-up
  191. for (var i = 0; i < 3; i++)
  192. {
  193. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  194. _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
  195. }
  196. GC.Collect();
  197. GC.WaitForPendingFinalizers();
  198. GC.Collect();
  199. var stopwatch = new Stopwatch();
  200. stopwatch.Start();
  201. for (var i = 0; i < runCount; i++)
  202. _sshMessageFactory.DisableAndDeactivateMessage(messageName);
  203. GC.Collect();
  204. GC.WaitForPendingFinalizers();
  205. GC.Collect();
  206. stopwatch.Stop();
  207. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  208. stopwatch.Reset();
  209. stopwatch.Start();
  210. for (var i = 0; i < runCount; i++)
  211. _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
  212. GC.Collect();
  213. GC.WaitForPendingFinalizers();
  214. GC.Collect();
  215. stopwatch.Stop();
  216. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  217. }
  218. [TestMethod]
  219. public void Performance_DisableNonKeyExchangeMessages()
  220. {
  221. const int runCount = 1000000;
  222. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
  223. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_DEBUG");
  224. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
  225. _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
  226. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
  227. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_DEBUG");
  228. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
  229. _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
  230. // warm-up
  231. for (var i = 0; i < 3; i++)
  232. {
  233. _sshMessageFactory.DisableNonKeyExchangeMessages();
  234. _sshMessageFactory.EnableActivatedMessages();
  235. _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
  236. _sshMessageFactoryOriginal.EnableActivatedMessages();
  237. }
  238. //Console.WriteLine("Starting test");
  239. GC.Collect();
  240. GC.WaitForPendingFinalizers();
  241. GC.Collect();
  242. var stopwatch = new Stopwatch();
  243. stopwatch.Start();
  244. for (var i = 0; i < runCount; i++)
  245. {
  246. _sshMessageFactory.DisableNonKeyExchangeMessages();
  247. _sshMessageFactory.EnableActivatedMessages();
  248. }
  249. GC.Collect();
  250. GC.WaitForPendingFinalizers();
  251. GC.Collect();
  252. stopwatch.Stop();
  253. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  254. stopwatch.Reset();
  255. stopwatch.Start();
  256. for (var i = 0; i < runCount; i++)
  257. {
  258. _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
  259. _sshMessageFactoryOriginal.EnableActivatedMessages();
  260. }
  261. GC.Collect();
  262. GC.WaitForPendingFinalizers();
  263. GC.Collect();
  264. stopwatch.Stop();
  265. Console.WriteLine(stopwatch.ElapsedMilliseconds);
  266. }
  267. internal class SshMessageFactoryOriginal
  268. {
  269. private readonly IEnumerable<MessageMetadata> _messagesMetadata;
  270. public SshMessageFactoryOriginal()
  271. {
  272. _messagesMetadata = new[]
  273. {
  274. new MessageMetadata {Name = "SSH_MSG_NEWKEYS", Number = 21, Type = typeof(NewKeysMessage)},
  275. new MessageMetadata
  276. {
  277. Name = "SSH_MSG_REQUEST_FAILURE",
  278. Number = 82,
  279. Type = typeof(RequestFailureMessage)
  280. },
  281. new MessageMetadata {Name = "SSH_MSG_KEXINIT", Number = 20, Type = typeof(KeyExchangeInitMessage)},
  282. new MessageMetadata
  283. {
  284. Name = "SSH_MSG_CHANNEL_OPEN_FAILURE",
  285. Number = 92,
  286. Type = typeof(ChannelOpenFailureMessage)
  287. },
  288. new MessageMetadata
  289. {
  290. Name = "SSH_MSG_CHANNEL_FAILURE",
  291. Number = 100,
  292. Type = typeof(ChannelFailureMessage)
  293. },
  294. new MessageMetadata
  295. {
  296. Name = "SSH_MSG_CHANNEL_EXTENDED_DATA",
  297. Number = 95,
  298. Type = typeof(ChannelExtendedDataMessage)
  299. },
  300. new MessageMetadata
  301. {
  302. Name = "SSH_MSG_CHANNEL_DATA",
  303. Number = 94,
  304. Type = typeof(ChannelDataMessage)
  305. },
  306. new MessageMetadata
  307. {
  308. Name = "SSH_MSG_USERAUTH_REQUEST",
  309. Number = 50,
  310. Type = typeof(RequestMessage)
  311. },
  312. new MessageMetadata
  313. {
  314. Name = "SSH_MSG_CHANNEL_REQUEST",
  315. Number = 98,
  316. Type = typeof(ChannelRequestMessage)
  317. },
  318. new MessageMetadata
  319. {
  320. Name = "SSH_MSG_USERAUTH_BANNER",
  321. Number = 53,
  322. Type = typeof(BannerMessage)
  323. },
  324. new MessageMetadata
  325. {
  326. Name = "SSH_MSG_USERAUTH_INFO_RESPONSE",
  327. Number = 61,
  328. Type = typeof(InformationResponseMessage)
  329. },
  330. new MessageMetadata
  331. {
  332. Name = "SSH_MSG_USERAUTH_FAILURE",
  333. Number = 51,
  334. Type = typeof(FailureMessage)
  335. },
  336. new MessageMetadata {Name = "SSH_MSG_DEBUG", Number = 4, Type = typeof(DebugMessage),},
  337. new MessageMetadata
  338. {
  339. Name = "SSH_MSG_KEXDH_INIT",
  340. Number = 30,
  341. Type = typeof(KeyExchangeDhInitMessage)
  342. },
  343. new MessageMetadata
  344. {
  345. Name = "SSH_MSG_GLOBAL_REQUEST",
  346. Number = 80,
  347. Type = typeof(GlobalRequestMessage)
  348. },
  349. new MessageMetadata
  350. {
  351. Name = "SSH_MSG_CHANNEL_OPEN",
  352. Number = 90,
  353. Type = typeof(ChannelOpenMessage)
  354. },
  355. new MessageMetadata
  356. {
  357. Name = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
  358. Number = 91,
  359. Type = typeof(ChannelOpenConfirmationMessage)
  360. },
  361. new MessageMetadata
  362. {
  363. Name = "SSH_MSG_USERAUTH_INFO_REQUEST",
  364. Number = 60,
  365. Type = typeof(InformationRequestMessage)
  366. },
  367. new MessageMetadata
  368. {
  369. Name = "SSH_MSG_UNIMPLEMENTED",
  370. Number = 3,
  371. Type = typeof(UnimplementedMessage)
  372. },
  373. new MessageMetadata
  374. {
  375. Name = "SSH_MSG_REQUEST_SUCCESS",
  376. Number = 81,
  377. Type = typeof(RequestSuccessMessage)
  378. },
  379. new MessageMetadata
  380. {
  381. Name = "SSH_MSG_CHANNEL_SUCCESS",
  382. Number = 99,
  383. Type = typeof(ChannelSuccessMessage)
  384. },
  385. new MessageMetadata
  386. {
  387. Name = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ",
  388. Number = 60,
  389. Type = typeof(PasswordChangeRequiredMessage)
  390. },
  391. new MessageMetadata {Name = "SSH_MSG_DISCONNECT", Number = 1, Type = typeof(DisconnectMessage)},
  392. new MessageMetadata
  393. {
  394. Name = "SSH_MSG_SERVICE_REQUEST",
  395. Number = 5,
  396. Type = typeof(ServiceRequestMessage)
  397. },
  398. new MessageMetadata
  399. {
  400. Name = "SSH_MSG_KEX_DH_GEX_REQUEST",
  401. Number = 34,
  402. Type = typeof(KeyExchangeDhGroupExchangeRequest)
  403. },
  404. new MessageMetadata
  405. {
  406. Name = "SSH_MSG_KEX_DH_GEX_GROUP",
  407. Number = 31,
  408. Type = typeof(KeyExchangeDhGroupExchangeGroup)
  409. },
  410. new MessageMetadata
  411. {
  412. Name = "SSH_MSG_USERAUTH_SUCCESS",
  413. Number = 52,
  414. Type = typeof(SuccessMessage)
  415. },
  416. new MessageMetadata
  417. {
  418. Name = "SSH_MSG_USERAUTH_PK_OK",
  419. Number = 60,
  420. Type = typeof(PublicKeyMessage)
  421. },
  422. new MessageMetadata {Name = "SSH_MSG_IGNORE", Number = 2, Type = typeof(IgnoreMessage)},
  423. new MessageMetadata
  424. {
  425. Name = "SSH_MSG_CHANNEL_WINDOW_ADJUST",
  426. Number = 93,
  427. Type = typeof(ChannelWindowAdjustMessage)
  428. },
  429. new MessageMetadata
  430. {
  431. Name = "SSH_MSG_CHANNEL_EOF",
  432. Number = 96,
  433. Type = typeof(ChannelEofMessage)
  434. },
  435. new MessageMetadata
  436. {
  437. Name = "SSH_MSG_CHANNEL_CLOSE",
  438. Number = 97,
  439. Type = typeof(ChannelCloseMessage)
  440. },
  441. new MessageMetadata
  442. {
  443. Name = "SSH_MSG_SERVICE_ACCEPT",
  444. Number = 6,
  445. Type = typeof(ServiceAcceptMessage)
  446. },
  447. new MessageMetadata
  448. {
  449. Name = "SSH_MSG_KEXDH_REPLY",
  450. Number = 31,
  451. Type = typeof(KeyExchangeDhReplyMessage)
  452. },
  453. new MessageMetadata
  454. {
  455. Name = "SSH_MSG_KEX_DH_GEX_INIT",
  456. Number = 32,
  457. Type = typeof(KeyExchangeDhGroupExchangeInit)
  458. },
  459. new MessageMetadata
  460. {
  461. Name = "SSH_MSG_KEX_DH_GEX_REPLY",
  462. Number = 33,
  463. Type = typeof(KeyExchangeDhGroupExchangeReply)
  464. }
  465. };
  466. }
  467. /// <summary>
  468. /// Disables and deactivate all messages.
  469. /// </summary>
  470. public void Reset()
  471. {
  472. foreach (var messageMetadata in _messagesMetadata)
  473. {
  474. messageMetadata.Activated = messageMetadata.Enabled = false;
  475. }
  476. }
  477. public void EnableActivatedMessages()
  478. {
  479. foreach (var messageMetadata in _messagesMetadata)
  480. {
  481. if (messageMetadata.Activated)
  482. messageMetadata.Enabled = true;
  483. }
  484. }
  485. public Message Create(byte messageNumber)
  486. {
  487. var messageMetadata =
  488. (from m in _messagesMetadata where m.Number == messageNumber && m.Enabled && m.Activated select m)
  489. .FirstOrDefault();
  490. if (messageMetadata == null)
  491. throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.",
  492. messageNumber));
  493. return messageMetadata.Type.CreateInstance<Message>();
  494. }
  495. public void DisableNonKeyExchangeMessages()
  496. {
  497. foreach (var messageMetadata in _messagesMetadata)
  498. {
  499. if (messageMetadata.Activated && messageMetadata.Number > 2 &&
  500. (messageMetadata.Number < 20 || messageMetadata.Number > 30))
  501. {
  502. //Console.WriteLine("Disabling " + messageMetadata.Name + "...");
  503. messageMetadata.Enabled = false;
  504. }
  505. }
  506. }
  507. public void EnableAndActivateMessage(string messageName)
  508. {
  509. lock (_messagesMetadata)
  510. {
  511. var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
  512. foreach (var messageMetadata in messagesMetadata)
  513. messageMetadata.Enabled = messageMetadata.Activated = true;
  514. }
  515. }
  516. public void DisableAndDeactivateMessage(string messageName)
  517. {
  518. lock (_messagesMetadata)
  519. {
  520. var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
  521. foreach (var messageMetadata in messagesMetadata)
  522. messageMetadata.Enabled = messageMetadata.Activated = false;
  523. }
  524. }
  525. private class MessageMetadata
  526. {
  527. public string Name { get; set; }
  528. public byte Number { get; set; }
  529. public bool Enabled { get; set; }
  530. public bool Activated { get; set; }
  531. public Type Type { get; set; }
  532. }
  533. }
  534. }
  535. }