PageRenderTime 50ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Connection.cs

https://bitbucket.org/danipen/mono
C# | 1718 lines | 995 code | 151 blank | 572 comment | 117 complexity | e4cc64c1d756e912058505e0ed256993 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /******************************************************************************
  2. * The MIT License
  3. * Copyright (c) 2003 Novell Inc. www.novell.com
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the Software), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. * SOFTWARE.
  22. *******************************************************************************/
  23. //
  24. // Novell.Directory.Ldap.Connection.cs
  25. //
  26. // Author:
  27. // Sunil Kumar (Sunilk@novell.com)
  28. //
  29. // (C) 2003 Novell, Inc (http://www.novell.com)
  30. //
  31. using System;
  32. using System.Threading;
  33. using Novell.Directory.Ldap.Asn1;
  34. using Novell.Directory.Ldap.Rfc2251;
  35. using Novell.Directory.Ldap.Utilclass;
  36. #if !TARGET_JVM
  37. using Mono.Security.Protocol.Tls;
  38. using Mono.Security.X509.Extensions;
  39. #endif
  40. using Syscert = System.Security.Cryptography.X509Certificates;
  41. using System.Security.Cryptography;
  42. using System.Net;
  43. using System.Net.Sockets;
  44. using System.Collections;
  45. using System.IO;
  46. using System.Text;
  47. #if !TARGET_JVM
  48. using Mono.Security.X509;
  49. #endif
  50. using System.Text.RegularExpressions;
  51. using System.Globalization;
  52. using System.Reflection;
  53. namespace Novell.Directory.Ldap
  54. {
  55. public delegate bool CertificateValidationCallback(
  56. Syscert.X509Certificate certificate,
  57. int[] certificateErrors);
  58. /// <summary> The class that creates a connection to the Ldap server. After the
  59. /// connection is made, a thread is created that reads data from the
  60. /// connection.
  61. ///
  62. /// The application's thread sends a request to the MessageAgent class, which
  63. /// creates a Message class. The Message class calls the writeMessage method
  64. /// of this class to send the request to the server. The application thread
  65. /// will then query the MessageAgent class for a response.
  66. ///
  67. /// The reader thread multiplexes response messages received from the
  68. /// server to the appropriate Message class. Each Message class
  69. /// has its own message queue.
  70. ///
  71. /// Unsolicited messages are process separately, and if the application
  72. /// has registered a handler, a separate thread is created for that
  73. /// application's handler to process the message.
  74. ///
  75. /// Note: the reader thread must not be a "selfish" thread, since some
  76. /// operating systems do not time slice.
  77. ///
  78. /// </summary>
  79. /*package*/
  80. sealed class Connection
  81. {
  82. public event CertificateValidationCallback OnCertificateValidation;
  83. public enum CertificateProblem : long
  84. {
  85. CertEXPIRED = 0x800B0101,
  86. CertVALIDITYPERIODNESTING = 0x800B0102,
  87. CertROLE = 0x800B0103,
  88. CertPATHLENCONST = 0x800B0104,
  89. CertCRITICAL = 0x800B0105,
  90. CertPURPOSE = 0x800B0106,
  91. CertISSUERCHAINING = 0x800B0107,
  92. CertMALFORMED = 0x800B0108,
  93. CertUNTRUSTEDROOT = 0x800B0109,
  94. CertCHAINING = 0x800B010A,
  95. CertREVOKED = 0x800B010C,
  96. CertUNTRUSTEDTESTROOT = 0x800B010D,
  97. CertREVOCATION_FAILURE = 0x800B010E,
  98. CertCN_NO_MATCH = 0x800B010F,
  99. CertWRONG_USAGE = 0x800B0110,
  100. CertUNTRUSTEDCA = 0x800B0112
  101. }
  102. private static String GetProblemMessage(CertificateProblem Problem)
  103. {
  104. String ProblemMessage = "";
  105. String ProblemCodeName = CertificateProblem.GetName(typeof(CertificateProblem), Problem);
  106. if(ProblemCodeName != null)
  107. ProblemMessage = ProblemMessage + ProblemCodeName;
  108. else
  109. ProblemMessage = "Unknown Certificate Problem";
  110. return ProblemMessage;
  111. }
  112. private ArrayList handshakeProblemsEncountered = new ArrayList();
  113. private void InitBlock()
  114. {
  115. writeSemaphore = new System.Object();
  116. encoder = new LBEREncoder();
  117. decoder = new LBERDecoder();
  118. stopReaderMessageID = CONTINUE_READING;
  119. messages = new MessageVector(5, 5);
  120. unsolicitedListeners = new System.Collections.ArrayList(3);
  121. }
  122. /// <summary> Indicates whether clones exist for LdapConnection
  123. ///
  124. /// </summary>
  125. /// <returns> true if clones exist, false otherwise.
  126. /// </returns>
  127. internal bool Cloned
  128. {
  129. /* package */
  130. get
  131. {
  132. return (cloneCount > 0);
  133. }
  134. }
  135. internal bool Ssl
  136. {
  137. get
  138. {
  139. return ssl;
  140. }
  141. set
  142. {
  143. ssl=value;
  144. }
  145. }
  146. /// <summary> gets the host used for this connection</summary>
  147. internal System.String Host
  148. {
  149. /* package */
  150. get
  151. {
  152. return host;
  153. }
  154. }
  155. /// <summary> gets the port used for this connection</summary>
  156. internal int Port
  157. {
  158. /* package */
  159. get
  160. {
  161. return port;
  162. }
  163. }
  164. /// <summary> gets the writeSemaphore id used for active bind operation</summary>
  165. /// <summary> sets the writeSemaphore id used for active bind operation</summary>
  166. internal int BindSemId
  167. {
  168. /* package */
  169. get
  170. {
  171. return bindSemaphoreId;
  172. }
  173. /* package */
  174. set
  175. {
  176. bindSemaphoreId = value;
  177. return ;
  178. }
  179. }
  180. /// <summary> checks if the writeSemaphore id used for active bind operation is clear</summary>
  181. internal bool BindSemIdClear
  182. {
  183. /* package */
  184. get
  185. {
  186. if (bindSemaphoreId == 0)
  187. {
  188. return true;
  189. }
  190. return false;
  191. }
  192. }
  193. /// <summary> Return whether the application is bound to this connection.
  194. /// Note: an anonymous bind returns false - not bound
  195. /// </summary>
  196. internal bool Bound
  197. {
  198. /* package */
  199. get
  200. {
  201. if (bindProperties != null)
  202. {
  203. // Bound if not anonymous
  204. return (!bindProperties.Anonymous);
  205. }
  206. return false;
  207. }
  208. }
  209. /// <summary> Return whether a connection has been made</summary>
  210. internal bool Connected
  211. {
  212. /* package */
  213. get
  214. {
  215. return (in_Renamed != null);
  216. }
  217. }
  218. /// <summary>
  219. /// Sets the authentication credentials in the object
  220. /// and set flag indicating successful bind.
  221. ///
  222. ///
  223. ///
  224. /// </summary>
  225. /// <returns> The BindProperties object for this connection.
  226. /// </returns>
  227. /// <summary>
  228. /// Sets the authentication credentials in the object
  229. /// and set flag indicating successful bind.
  230. ///
  231. ///
  232. ///
  233. /// </summary>
  234. /// <param name="bindProps"> The BindProperties object to set.
  235. /// </param>
  236. internal BindProperties BindProperties
  237. {
  238. /* package */
  239. get
  240. {
  241. return bindProperties;
  242. }
  243. /* package */
  244. set
  245. {
  246. bindProperties = value;
  247. return ;
  248. }
  249. }
  250. /// <summary> Gets the current referral active on this connection if created to
  251. /// follow referrals.
  252. ///
  253. /// </summary>
  254. /// <returns> the active referral url
  255. /// </returns>
  256. /// <summary> Sets the current referral active on this connection if created to
  257. /// follow referrals.
  258. /// </summary>
  259. internal ReferralInfo ActiveReferral
  260. {
  261. get
  262. {
  263. return activeReferral;
  264. }
  265. set
  266. {
  267. activeReferral = value;
  268. return ;
  269. }
  270. }
  271. /// <summary> Returns the name of this Connection, used for debug only
  272. ///
  273. /// </summary>
  274. /// <returns> the name of this connection
  275. /// </returns>
  276. internal System.String ConnectionName
  277. {
  278. /*package*/
  279. get
  280. {
  281. return name;
  282. }
  283. }
  284. private System.Object writeSemaphore;
  285. private int writeSemaphoreOwner = 0;
  286. private int writeSemaphoreCount = 0;
  287. // We need a message number for disconnect to grab the semaphore,
  288. // but may not have one, so we invent a unique one.
  289. private int ephemeralId = - 1;
  290. private BindProperties bindProperties = null;
  291. private int bindSemaphoreId = 0; // 0 is never used by to lock a semaphore
  292. private Thread reader = null; // New thread that reads data from the server.
  293. private Thread deadReader = null; // Identity of last reader thread
  294. private System.IO.IOException deadReaderException = null; // Last exception of reader
  295. private LBEREncoder encoder;
  296. private LBERDecoder decoder;
  297. /*
  298. * socket is the current socket being used.
  299. * nonTLSBackup is the backup socket if startTLS is called.
  300. * if nonTLSBackup is null then startTLS has not been called,
  301. * or stopTLS has been called to end TLS protection
  302. */
  303. private System.Net.Sockets.Socket sock = null;
  304. private System.Net.Sockets.TcpClient socket = null;
  305. private System.Net.Sockets.TcpClient nonTLSBackup = null;
  306. private System.IO.Stream in_Renamed = null;
  307. private System.IO.Stream out_Renamed = null;
  308. // When set to true the client connection is up and running
  309. private bool clientActive = true;
  310. private bool ssl = false;
  311. // Indicates we have received a server shutdown unsolicited notification
  312. private bool unsolSvrShutDnNotification = false;
  313. // Ldap message IDs are all positive numbers so we can use negative
  314. // numbers as flags. This are flags assigned to stopReaderMessageID
  315. // to tell the reader what state we are in.
  316. private const int CONTINUE_READING = - 99;
  317. private const int STOP_READING = - 98;
  318. // Stops the reader thread when a Message with the passed-in ID is read.
  319. // This parameter is set by stopReaderOnReply and stopTLS
  320. private int stopReaderMessageID;
  321. // Place to save message information classes
  322. private MessageVector messages;
  323. // Connection created to follow referral
  324. private ReferralInfo activeReferral = null;
  325. // Place to save unsolicited message listeners
  326. private System.Collections.ArrayList unsolicitedListeners;
  327. // The LdapSocketFactory to be used as the default to create new connections
  328. // private static LdapSocketFactory socketFactory = null;
  329. // The LdapSocketFactory used for this connection
  330. // private LdapSocketFactory mySocketFactory;
  331. private System.String host = null;
  332. private int port = 0;
  333. // Number of clones in addition to original LdapConnection using this
  334. // connection.
  335. private int cloneCount = 0;
  336. // Connection number & name used only for debug
  337. private System.String name = "";
  338. private static System.Object nameLock; // protect connNum
  339. private static int connNum = 0;
  340. // These attributes can be retreived using the getProperty
  341. // method in LdapConnection. Future releases might require
  342. // these to be local variables that can be modified using
  343. // the setProperty method.
  344. /* package */
  345. internal static System.String sdk;
  346. /* package */
  347. internal static System.Int32 protocol;
  348. /* package */
  349. internal static System.String security = "simple";
  350. /// <summary> Create a new Connection object
  351. ///
  352. /// </summary>
  353. /// <param name="factory">specifies the factory to use to produce SSL sockets.
  354. /// </param>
  355. /* package */
  356. // internal Connection(LdapSocketFactory factory)
  357. internal Connection()
  358. {
  359. InitBlock();
  360. return ;
  361. }
  362. /// <summary> Copy this Connection object.
  363. ///
  364. /// This is not a true clone, but creates a new object encapsulating
  365. /// part of the connection information from the original object.
  366. /// The new object will have the same default socket factory,
  367. /// designated socket factory, host, port, and protocol version
  368. /// as the original object.
  369. /// The new object is NOT be connected to the host.
  370. ///
  371. /// </summary>
  372. /// <returns> a shallow copy of this object
  373. /// </returns>
  374. /* package */
  375. internal System.Object copy()
  376. {
  377. Connection c = new Connection();
  378. c.host = this.host;
  379. c.port = this.port;
  380. Novell.Directory.Ldap.Connection.protocol = Connection.protocol;
  381. return c;
  382. }
  383. /// <summary> Acquire a simple counting semaphore that synchronizes state affecting
  384. /// bind. This method generates an ephemeral message id (negative number).
  385. ///
  386. /// We bind using the message ID because a different thread may unlock
  387. /// the semaphore than the one that set it. It is cleared when the
  388. /// response to the bind is processed, or when the bind operation times out.
  389. ///
  390. /// Returns when the semaphore is acquired
  391. ///
  392. /// </summary>
  393. /// <returns> the ephemeral message id that identifies semaphore's owner
  394. /// </returns>
  395. /* package */
  396. internal int acquireWriteSemaphore()
  397. {
  398. return acquireWriteSemaphore(0);
  399. }
  400. /// <summary> Acquire a simple counting semaphore that synchronizes state affecting
  401. /// bind. The semaphore is held by setting a value in writeSemaphoreOwner.
  402. ///
  403. /// We bind using the message ID because a different thread may unlock
  404. /// the semaphore than the one that set it. It is cleared when the
  405. /// response to the bind is processed, or when the bind operation times out.
  406. /// Returns when the semaphore is acquired.
  407. ///
  408. /// </summary>
  409. /// <param name="msgId">a value that identifies the owner of this semaphore. A
  410. /// value of zero means assign a unique semaphore value.
  411. ///
  412. /// </param>
  413. /// <returns> the semaphore value used to acquire the lock
  414. /// </returns>
  415. /* package */
  416. internal int acquireWriteSemaphore(int msgId)
  417. {
  418. int id = msgId;
  419. lock (writeSemaphore)
  420. {
  421. if (id == 0)
  422. {
  423. ephemeralId = ((ephemeralId == System.Int32.MinValue)?(ephemeralId = - 1):--ephemeralId);
  424. id = ephemeralId;
  425. }
  426. while (true)
  427. {
  428. if (writeSemaphoreOwner == 0)
  429. {
  430. // we have acquired the semahpore
  431. writeSemaphoreOwner = id;
  432. break;
  433. }
  434. else
  435. {
  436. if (writeSemaphoreOwner == id)
  437. {
  438. // we already own the semahpore
  439. break;
  440. }
  441. try
  442. {
  443. // Keep trying for the lock
  444. System.Threading.Monitor.Wait(writeSemaphore);
  445. continue;
  446. }
  447. catch (System.Threading.ThreadInterruptedException ex)
  448. {
  449. // Keep trying for the lock
  450. continue;
  451. }
  452. }
  453. }
  454. writeSemaphoreCount++;
  455. }
  456. return id;
  457. }
  458. /// <summary> Release a simple counting semaphore that synchronizes state affecting
  459. /// bind. Frees the semaphore when number of acquires and frees for this
  460. /// thread match.
  461. ///
  462. /// </summary>
  463. /// <param name="msgId">a value that identifies the owner of this semaphore
  464. /// </param>
  465. /* package */
  466. internal void freeWriteSemaphore(int msgId)
  467. {
  468. lock (writeSemaphore)
  469. {
  470. if (writeSemaphoreOwner == 0)
  471. {
  472. throw new System.SystemException("Connection.freeWriteSemaphore(" + msgId + "): semaphore not owned by any thread");
  473. }
  474. else if (writeSemaphoreOwner != msgId)
  475. {
  476. throw new System.SystemException("Connection.freeWriteSemaphore(" + msgId + "): thread does not own the semaphore, owned by " + writeSemaphoreOwner);
  477. }
  478. // if all instances of this semaphore for this thread are released,
  479. // wake up all threads waiting.
  480. if (--writeSemaphoreCount == 0)
  481. {
  482. writeSemaphoreOwner = 0;
  483. System.Threading.Monitor.Pulse(writeSemaphore);
  484. }
  485. }
  486. return ;
  487. }
  488. /*
  489. * Wait until the reader thread ID matches the specified parameter.
  490. * Null = wait for the reader to terminate
  491. * Non Null = wait for the reader to start
  492. * Returns when the ID matches, i.e. reader stopped, or reader started.
  493. *
  494. * @param the thread id to match
  495. */
  496. private void waitForReader(Thread thread)
  497. {
  498. // wait for previous reader thread to terminate
  499. System.Threading.Thread rInst;
  500. System.Threading.Thread tInst;
  501. if(reader!=null)
  502. {
  503. rInst=reader;
  504. }
  505. else
  506. {
  507. rInst=null;
  508. }
  509. if(thread!=null)
  510. {
  511. tInst=thread;
  512. }
  513. else
  514. {
  515. tInst=null;
  516. }
  517. // while (reader != thread)
  518. while (!Object.Equals(rInst,tInst))
  519. {
  520. // Don't initialize connection while previous reader thread still
  521. // active.
  522. try
  523. {
  524. /*
  525. * The reader thread may start and immediately terminate.
  526. * To prevent the waitForReader from waiting forever
  527. * for the dead to rise, we leave traces of the deceased.
  528. * If the thread is already gone, we throw an exception.
  529. */
  530. if (thread == deadReader)
  531. {
  532. if (thread == null)
  533. /* then we wanted a shutdown */
  534. return ;
  535. System.IO.IOException lex = deadReaderException;
  536. deadReaderException = null;
  537. deadReader = null;
  538. // Reader thread terminated
  539. throw new LdapException(ExceptionMessages.CONNECTION_READER, LdapException.CONNECT_ERROR, null, lex);
  540. }
  541. lock (this)
  542. {
  543. System.Threading.Monitor.Wait(this, TimeSpan.FromMilliseconds(5));
  544. }
  545. }
  546. catch (System.Threading.ThreadInterruptedException ex)
  547. {
  548. ;
  549. }
  550. if(reader!=null)
  551. {
  552. rInst=reader;
  553. }
  554. else
  555. {
  556. rInst=null;
  557. }
  558. if(thread!=null)
  559. {
  560. tInst=thread;
  561. }
  562. else
  563. {
  564. tInst=null;
  565. }
  566. }
  567. deadReaderException = null;
  568. deadReader = null;
  569. return ;
  570. }
  571. /// <summary> Constructs a TCP/IP connection to a server specified in host and port.
  572. ///
  573. /// </summary>
  574. /// <param name="host">The host to connect to.
  575. ///
  576. /// </param>
  577. /// <param name="port">The port on the host to connect to.
  578. /// </param>
  579. /* package */
  580. internal void connect(System.String host, int port)
  581. {
  582. connect(host, port, 0);
  583. return ;
  584. }
  585. /****************************************************************************/
  586. public bool ServerCertificateValidation(
  587. Syscert.X509Certificate certificate,
  588. int[] certificateErrors)
  589. {
  590. if (null != OnCertificateValidation)
  591. {
  592. return OnCertificateValidation(certificate, certificateErrors);
  593. }
  594. return DefaultCertificateValidationHandler(certificate, certificateErrors);
  595. }
  596. public bool DefaultCertificateValidationHandler(
  597. Syscert.X509Certificate certificate,
  598. int[] certificateErrors)
  599. {
  600. bool retFlag=false;
  601. if (certificateErrors != null &&
  602. certificateErrors.Length > 0)
  603. {
  604. if( certificateErrors.Length==1 && certificateErrors[0] == -2146762481)
  605. {
  606. retFlag = true;
  607. }
  608. else
  609. {
  610. Console.WriteLine("Detected errors in the Server Certificate:");
  611. for (int i = 0; i < certificateErrors.Length; i++)
  612. {
  613. handshakeProblemsEncountered.Add((CertificateProblem)((uint)certificateErrors[i]));
  614. Console.WriteLine(certificateErrors[i]);
  615. }
  616. retFlag = false;
  617. }
  618. }
  619. else
  620. {
  621. retFlag = true;
  622. }
  623. // Skip the server cert errors.
  624. return retFlag;
  625. }
  626. /***********************************************************************/
  627. /// <summary> Constructs a TCP/IP connection to a server specified in host and port.
  628. /// Starts the reader thread.
  629. ///
  630. /// </summary>
  631. /// <param name="host">The host to connect to.
  632. ///
  633. /// </param>
  634. /// <param name="port">The port on the host to connect to.
  635. ///
  636. /// </param>
  637. /// <param name="semaphoreId">The write semaphore ID to use for the connect
  638. /// </param>
  639. private void connect(System.String host, int port, int semaphoreId)
  640. {
  641. /* Synchronized so all variables are in a consistant state and
  642. * so that another thread isn't doing a connect, disconnect, or clone
  643. * at the same time.
  644. */
  645. // Wait for active reader to terminate
  646. waitForReader(null);
  647. // Clear the server shutdown notification flag. This should already
  648. // be false unless of course we are reusing the same Connection object
  649. // after a server shutdown notification
  650. unsolSvrShutDnNotification = false;
  651. int semId = acquireWriteSemaphore(semaphoreId);
  652. try {
  653. // Make socket connection to specified host and port
  654. if (port == 0)
  655. {
  656. port = 389;//LdapConnection.DEFAULT_PORT;
  657. }
  658. try
  659. {
  660. if ((in_Renamed == null) || (out_Renamed == null))
  661. {
  662. #if !TARGET_JVM
  663. if(Ssl)
  664. {
  665. this.host = host;
  666. this.port = port;
  667. this.sock = new Socket ( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
  668. IPAddress hostadd = Dns.Resolve(host).AddressList[0];
  669. IPEndPoint ephost = new IPEndPoint(hostadd,port);
  670. sock.Connect(ephost);
  671. NetworkStream nstream = new NetworkStream(sock,true);
  672. // Load Mono.Security.dll
  673. Assembly a;
  674. try
  675. {
  676. a = Assembly.LoadWithPartialName("Mono.Security");
  677. }
  678. catch(System.IO.FileNotFoundException)
  679. {
  680. throw new LdapException(ExceptionMessages.SSL_PROVIDER_MISSING, LdapException.SSL_PROVIDER_NOT_FOUND, null);
  681. }
  682. Type tSslClientStream = a.GetType("Mono.Security.Protocol.Tls.SslClientStream");
  683. BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public |
  684. BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
  685. object[] consArgs = new object[4];
  686. consArgs[0] = nstream;
  687. consArgs[1] = host;
  688. consArgs[2] = false;
  689. Type tSecurityProtocolType = a.GetType("Mono.Security.Protocol.Tls.SecurityProtocolType");
  690. Enum objSPType = (Enum)(Activator.CreateInstance(tSecurityProtocolType));
  691. int nSsl3Val = (int) Enum.Parse(tSecurityProtocolType, "Ssl3");
  692. int nTlsVal = (int) Enum.Parse(tSecurityProtocolType, "Tls");
  693. consArgs[3] = Enum.ToObject(tSecurityProtocolType, nSsl3Val | nTlsVal);
  694. object objSslClientStream =
  695. Activator.CreateInstance(tSslClientStream, consArgs);
  696. // Register ServerCertValidationDelegate handler
  697. PropertyInfo pi = tSslClientStream.GetProperty("ServerCertValidationDelegate");
  698. pi.SetValue(objSslClientStream,
  699. Delegate.CreateDelegate(pi.PropertyType, this, "ServerCertificateValidation"),
  700. null);
  701. // Get the in and out streams
  702. in_Renamed = (System.IO.Stream) objSslClientStream;
  703. out_Renamed = (System.IO.Stream) objSslClientStream;
  704. /*
  705. SslClientStream sslstream = new SslClientStream(
  706. nstream,
  707. host,
  708. false,
  709. Mono.Security.Protocol.Tls.SecurityProtocolType.Ssl3|Mono.Security.Protocol.Tls.SecurityProtocolType.Tls);
  710. sslstream.ServerCertValidationDelegate += new CertificateValidationCallback(ServerCertificateValidation);*/
  711. // byte[] buffer = new byte[0];
  712. // sslstream.Read(buffer, 0, buffer.Length);
  713. // sslstream.doHandshake();
  714. /*
  715. in_Renamed = (System.IO.Stream) sslstream;
  716. out_Renamed = (System.IO.Stream) sslstream;*/
  717. }
  718. else{
  719. #endif
  720. socket = new System.Net.Sockets.TcpClient(host, port);
  721. in_Renamed = (System.IO.Stream) socket.GetStream();
  722. out_Renamed = (System.IO.Stream) socket.GetStream();
  723. #if !TARGET_JVM
  724. }
  725. #endif
  726. }
  727. else
  728. {
  729. Console.WriteLine( "connect input/out Stream specified");
  730. }
  731. }
  732. catch (System.Net.Sockets.SocketException se)
  733. {
  734. // Unable to connect to server host:port
  735. sock = null;
  736. socket = null;
  737. throw new LdapException(ExceptionMessages.CONNECTION_ERROR, new System.Object[] { host, port }, LdapException.CONNECT_ERROR, null, se);
  738. }
  739. catch (System.IO.IOException ioe)
  740. {
  741. // Unable to connect to server host:port
  742. sock = null;
  743. socket = null;
  744. throw new LdapException(ExceptionMessages.CONNECTION_ERROR, new System.Object[]{host, port}, LdapException.CONNECT_ERROR, null, ioe);
  745. }
  746. // Set host and port
  747. this.host = host;
  748. this.port = port;
  749. // start the reader thread
  750. this.startReader();
  751. clientActive = true; // Client is up
  752. } finally {
  753. freeWriteSemaphore(semId);
  754. }
  755. return;
  756. }
  757. /// <summary> Increments the count of cloned connections</summary>
  758. /* package */
  759. internal void incrCloneCount()
  760. {
  761. lock (this)
  762. {
  763. cloneCount++;
  764. return ;
  765. }
  766. }
  767. /// <summary> Destroys a clone of <code>LdapConnection</code>.
  768. ///
  769. /// This method first determines if only one <code>LdapConnection</code>
  770. /// object is associated with this connection, i.e. if no clone exists.
  771. ///
  772. /// If no clone exists, the socket is closed, and the current
  773. /// <code>Connection</code> object is returned.
  774. ///
  775. /// If multiple <code>LdapConnection</code> objects are associated
  776. /// with this connection, i.e. clones exist, a {@link #copy} of the
  777. /// this object is made, but is not connected to any host. This
  778. /// disassociates that clone from the original connection. The new
  779. /// <code>Connection</code> object is returned.
  780. ///
  781. /// Only one destroyClone instance is allowed to run at any one time.
  782. ///
  783. /// If the connection is closed, any threads waiting for operations
  784. /// on that connection will wake with an LdapException indicating
  785. /// the connection is closed.
  786. ///
  787. /// </summary>
  788. /// <param name="apiCall"><code>true</code> indicates the application is closing the
  789. /// connection or or creating a new one by calling either the
  790. /// <code>connect</code> or <code>disconnect</code> methods
  791. /// of <code>LdapConnection</code>. <code>false</code>
  792. /// indicates that <code>LdapConnection</code> is being finalized.
  793. ///
  794. /// </param>
  795. /// <returns> a Connection object or null if finalizing.
  796. /// </returns>
  797. /* package */
  798. internal Connection destroyClone(bool apiCall)
  799. {
  800. lock (this)
  801. {
  802. Connection conn = this;
  803. if (cloneCount > 0)
  804. {
  805. cloneCount--;
  806. // This is a clone, set a new connection object.
  807. if (apiCall)
  808. {
  809. conn = (Connection) this.copy();
  810. }
  811. else
  812. {
  813. conn = null;
  814. }
  815. }
  816. else
  817. {
  818. if (in_Renamed != null)
  819. {
  820. // Not a clone and connected
  821. /*
  822. * Either the application has called disconnect or connect
  823. * resulting in the current connection being closed. If the
  824. * application has any queues waiting on messages, we
  825. * need wake these up so the application does not hang.
  826. * The boolean flag indicates whether the close came
  827. * from an API call or from the object being finalized.
  828. */
  829. InterThreadException notify = new InterThreadException((apiCall?ExceptionMessages.CONNECTION_CLOSED:ExceptionMessages.CONNECTION_FINALIZED), null, LdapException.CONNECT_ERROR, null, null);
  830. // Destroy old connection
  831. shutdown("destroy clone", 0, notify);
  832. }
  833. }
  834. return conn;
  835. }
  836. }
  837. /// <summary> sets the default socket factory
  838. ///
  839. /// </summary>
  840. /// <param name="factory">the default factory to set
  841. /// </param>
  842. /* package */
  843. /// <summary> gets the socket factory used for this connection
  844. ///
  845. /// </summary>
  846. /// <returns> the default factory for this connection
  847. /// </returns>
  848. /* package */
  849. /// <summary> clears the writeSemaphore id used for active bind operation</summary>
  850. /* package */
  851. internal void clearBindSemId()
  852. {
  853. bindSemaphoreId = 0;
  854. return ;
  855. }
  856. /// <summary> Writes an LdapMessage to the Ldap server over a socket.
  857. ///
  858. /// </summary>
  859. /// <param name="info">the Message containing the message to write.
  860. /// </param>
  861. /* package */
  862. internal void writeMessage(Message info)
  863. {
  864. ExceptionMessages em = new ExceptionMessages();
  865. System.Object [][]contents = em.getContents();
  866. messages.Add(info);
  867. // For bind requests, if not connected, attempt to reconnect
  868. if (info.BindRequest && (Connected == false) && ((System.Object) host != null))
  869. {
  870. connect(host, port, info.MessageID);
  871. }
  872. if(Connected == true)
  873. {
  874. LdapMessage msg = info.Request;
  875. writeMessage(msg);
  876. return ;
  877. }
  878. else
  879. {
  880. int errorcount=0;
  881. for(errorcount=0;errorcount<contents.Length;errorcount++)
  882. if(contents[errorcount][0]=="CONNECTION_CLOSED")
  883. break;
  884. throw new LdapException(ExceptionMessages.CONNECTION_CLOSED, new System.Object[]{host, port}, LdapException.CONNECT_ERROR, (String)contents[errorcount][1]);
  885. }
  886. }
  887. /// <summary> Writes an LdapMessage to the Ldap server over a socket.
  888. ///
  889. /// </summary>
  890. /// <param name="msg">the message to write.
  891. /// </param>
  892. /* package */
  893. internal void writeMessage(LdapMessage msg)
  894. {
  895. int id;
  896. // Get the correct semaphore id for bind operations
  897. if (bindSemaphoreId == 0)
  898. {
  899. // Semaphore id for normal operations
  900. id = msg.MessageID;
  901. }
  902. else
  903. {
  904. // Semaphore id for sasl bind operations
  905. id = bindSemaphoreId;
  906. }
  907. System.IO.Stream myOut = out_Renamed;
  908. acquireWriteSemaphore(id);
  909. try
  910. {
  911. if (myOut == null)
  912. {
  913. throw new System.IO.IOException("Output stream not initialized");
  914. }
  915. if (!(myOut.CanWrite))
  916. {
  917. return;
  918. }
  919. sbyte[] ber = msg.Asn1Object.getEncoding(encoder);
  920. myOut.Write(SupportClass.ToByteArray(ber), 0, ber.Length);
  921. myOut.Flush();
  922. }
  923. catch (System.IO.IOException ioe)
  924. {
  925. if ((msg.Type == LdapMessage.BIND_REQUEST) &&
  926. (ssl))
  927. {
  928. string strMsg = "Following problem(s) occurred while establishing SSL based Connection : ";
  929. if (handshakeProblemsEncountered.Count > 0)
  930. {
  931. strMsg += GetProblemMessage((CertificateProblem)handshakeProblemsEncountered[0]);
  932. for (int nProbIndex = 1; nProbIndex < handshakeProblemsEncountered.Count; nProbIndex++)
  933. {
  934. strMsg += ", " + GetProblemMessage((CertificateProblem)handshakeProblemsEncountered[nProbIndex]);
  935. }
  936. }
  937. else
  938. {
  939. strMsg += "Unknown Certificate Problem";
  940. }
  941. throw new LdapException(strMsg, new System.Object[]{host, port}, LdapException.SSL_HANDSHAKE_FAILED, null, ioe);
  942. }
  943. /*
  944. * IOException could be due to a server shutdown notification which
  945. * caused our Connection to quit. If so we send back a slightly
  946. * different error message. We could have checked this a little
  947. * earlier in the method but that would be an expensive check each
  948. * time we send out a message. Since this shutdown request is
  949. * going to be an infrequent occurence we check for it only when
  950. * we get an IOException. shutdown() will do the cleanup.
  951. */
  952. if (clientActive)
  953. {
  954. // We beliefe the connection was alive
  955. if (unsolSvrShutDnNotification)
  956. {
  957. // got server shutdown
  958. throw new LdapException(ExceptionMessages.SERVER_SHUTDOWN_REQ, new System.Object[]{host, port}, LdapException.CONNECT_ERROR, null, ioe);
  959. }
  960. // Other I/O Exceptions on host:port are reported as is
  961. throw new LdapException(ExceptionMessages.IO_EXCEPTION, new System.Object[]{host, port}, LdapException.CONNECT_ERROR, null, ioe);
  962. }
  963. }
  964. finally
  965. {
  966. freeWriteSemaphore(id);
  967. handshakeProblemsEncountered.Clear();
  968. }
  969. return ;
  970. }
  971. /// <summary> Returns the message agent for this msg ID</summary>
  972. /* package */
  973. internal MessageAgent getMessageAgent(int msgId)
  974. {
  975. Message info = messages.findMessageById(msgId);
  976. return info.MessageAgent;
  977. }
  978. /// <summary> Removes a Message class from the Connection's list
  979. ///
  980. /// </summary>
  981. /// <param name="info">the Message class to remove from the list
  982. /// </param>
  983. /* package */
  984. internal void removeMessage(Message info)
  985. {
  986. bool done = SupportClass.VectorRemoveElement(messages, info);
  987. return ;
  988. }
  989. /// <summary> Cleans up resources associated with this connection.</summary>
  990. ~Connection()
  991. {
  992. shutdown("Finalize", 0, null);
  993. return ;
  994. }
  995. /// <summary> Cleans up resources associated with this connection.
  996. /// This method may be called by finalize() for the connection, or it may
  997. /// be called by LdapConnection.disconnect().
  998. /// Should not have a writeSemaphore lock in place, as deadlock can occur
  999. /// while abandoning connections.
  1000. /// </summary>
  1001. private void shutdown(System.String reason, int semaphoreId, InterThreadException notifyUser)
  1002. {
  1003. Message info = null;
  1004. if (!clientActive)
  1005. {
  1006. return ;
  1007. }
  1008. clientActive = false;
  1009. while (true)
  1010. {
  1011. // remove messages from connection list and send abandon
  1012. try
  1013. {
  1014. System.Object temp_object;
  1015. temp_object = messages[0];
  1016. messages.RemoveAt(0);
  1017. info = (Message) temp_object;
  1018. }
  1019. catch (ArgumentOutOfRangeException ex)
  1020. {
  1021. // No more messages
  1022. break;
  1023. }
  1024. info.Abandon(null, notifyUser); // also notifies the application
  1025. }
  1026. int semId = acquireWriteSemaphore(semaphoreId);
  1027. // Now send unbind if socket not closed
  1028. if ((bindProperties != null) && (out_Renamed != null) && (out_Renamed.CanWrite) && (!bindProperties.Anonymous))
  1029. {
  1030. try
  1031. {
  1032. LdapMessage msg = new LdapUnbindRequest(null);
  1033. sbyte[] ber = msg.Asn1Object.getEncoding(encoder);
  1034. out_Renamed.Write(SupportClass.ToByteArray(ber), 0, ber.Length);
  1035. out_Renamed.Flush();
  1036. out_Renamed.Close();
  1037. }
  1038. catch (System.Exception ex)
  1039. {
  1040. ; // don't worry about error
  1041. }
  1042. }
  1043. bindProperties = null;
  1044. if (socket != null || sock != null)
  1045. {
  1046. #if !TARGET_JVM
  1047. // Just before closing the sockets, abort the reader thread
  1048. if ((reader != null) && (reason != "reader: thread stopping"))
  1049. reader.Abort();
  1050. #endif
  1051. // Close the socket
  1052. try
  1053. {
  1054. if(Ssl)
  1055. {
  1056. try {
  1057. sock.Shutdown(SocketShutdown.Both);
  1058. } catch {}
  1059. sock.Close();
  1060. }
  1061. else
  1062. {
  1063. if(in_Renamed != null)
  1064. in_Renamed.Close();
  1065. socket.Close();
  1066. }
  1067. }
  1068. catch (Exception)
  1069. {
  1070. // ignore problem closing socket
  1071. }
  1072. socket = null;
  1073. sock = null;
  1074. in_Renamed=null;
  1075. out_Renamed=null;
  1076. }
  1077. freeWriteSemaphore(semId);
  1078. return ;
  1079. }
  1080. /// <summary> This tests to see if there are any outstanding messages. If no messages
  1081. /// are in the queue it returns true. Each message will be tested to
  1082. /// verify that it is complete.
  1083. /// <I>The writeSemaphore must be set for this method to be reliable!</I>
  1084. ///
  1085. /// </summary>
  1086. /// <returns> true if no outstanding messages
  1087. /// </returns>
  1088. /* package */
  1089. internal bool areMessagesComplete()
  1090. {
  1091. System.Object[] messages = this.messages.ObjectArray;
  1092. int length = messages.Length;
  1093. // Check if SASL bind in progress
  1094. if (bindSemaphoreId != 0)
  1095. {
  1096. return false;
  1097. }
  1098. // Check if any messages queued
  1099. if (length == 0)
  1100. {
  1101. return true;
  1102. }
  1103. for (int i = 0; i < length; i++)
  1104. {
  1105. if (((Message) messages[i]).Complete == false)
  1106. return false;
  1107. }
  1108. return true;
  1109. }
  1110. /// <summary> The reader thread will stop when a reply is read with an ID equal
  1111. /// to the messageID passed in to this method. This is used by
  1112. /// LdapConnection.StartTLS.
  1113. /// </summary>
  1114. /* package */
  1115. internal void stopReaderOnReply(int messageID)
  1116. {
  1117. this.stopReaderMessageID = messageID;
  1118. return ;
  1119. }
  1120. /// <summary>startReader
  1121. /// startReader should be called when socket and io streams have been
  1122. /// set or changed. In particular after client.Connection.startTLS()
  1123. /// It assumes the reader thread is not running.
  1124. /// </summary>
  1125. /* package */
  1126. internal void startReader()
  1127. {
  1128. // Start Reader Thread
  1129. Thread r = new Thread(new ThreadStart(new ReaderThread(this).Run));
  1130. r.IsBackground = true; // If the last thread running, allow exit.
  1131. r.Start();
  1132. waitForReader(r);
  1133. return ;
  1134. }
  1135. /// <summary> Indicates if the conenction is using TLS protection
  1136. ///
  1137. /// Return true if using TLS protection
  1138. /// </summary>
  1139. internal bool TLS
  1140. {
  1141. get
  1142. {
  1143. return (this.nonTLSBackup != null);
  1144. }
  1145. }
  1146. /// <summary> StartsTLS, in this package, assumes the caller has:
  1147. /// 1) Acquired the writeSemaphore
  1148. /// 2) Stopped the reader thread
  1149. /// 3) checked that no messages are outstanding on this connection.
  1150. ///
  1151. /// After calling this method upper layers should start the reader
  1152. /// by calling startReader()
  1153. ///
  1154. /// In the client.Connection, StartTLS assumes Ldap.LdapConnection will
  1155. /// stop and start the reader thread. Connection.StopTLS will stop
  1156. /// and start the reader thread.
  1157. /// </summary>
  1158. /* package */
  1159. internal void startTLS()
  1160. {
  1161. #if !TARGET_JVM
  1162. try
  1163. {
  1164. waitForReader(null);
  1165. this.nonTLSBackup = this.socket;
  1166. /* this.sock = new Socket ( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
  1167. IPAddress hostadd = Dns.Resolve(host).AddressList[0];
  1168. IPEndPoint ephost = new IPEndPoint(hostadd,port);
  1169. sock.Connect(ephost);
  1170. */
  1171. // NetworkStream nstream = new NetworkStream(this.socket,true);
  1172. // Load Mono.Security.dll
  1173. Assembly a = null;
  1174. try
  1175. {
  1176. a = Assembly.LoadFrom("Mono.Security.dll");
  1177. }
  1178. catch(System.IO.FileNotFoundException)
  1179. {
  1180. throw new LdapException(ExceptionMessages.SSL_PROVIDER_MISSING, LdapException.SSL_PROVIDER_NOT_FOUND, null);
  1181. }
  1182. Type tSslClientStream = a.GetType("Mono.Security.Protocol.Tls.SslClientStream");
  1183. BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public |
  1184. BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
  1185. object[] consArgs = new object[4];
  1186. consArgs[0] = socket.GetStream();
  1187. consArgs[1] = host;
  1188. consArgs[2] = false;
  1189. Type tSecurityProtocolType = a.GetType("Mono.Security.Protocol.Tls.SecurityProtocolType");
  1190. Enum objSPType = (Enum)(Activator.CreateInstance(tSecurityProtocolType));
  1191. int nSsl3Val = (int) Enum.Parse(tSecurityProtocolType, "Ssl3");
  1192. int nTlsVal = (int) Enum.Parse(tSecurityProtocolType, "Tls");
  1193. consArgs[3] = Enum.ToObject(tSecurityProtocolType, nSsl3Val | nTlsVal);
  1194. object objSslClientStream =
  1195. Activator.CreateInstance(tSslClientStream, consArgs);
  1196. // Register ServerCertValidationDelegate handler
  1197. EventInfo ei = tSslClientStream.GetEvent("ServerCertValidationDelegate");
  1198. ei.AddEventHandler(objSslClientStream,
  1199. Delegate.CreateDelegate(ei.EventHandlerType, this, "ServerCertificateValidation"));
  1200. // Get the in and out streams
  1201. in_Renamed = (System.IO.Stream) objSslClientStream;
  1202. out_Renamed = (System.IO.Stream) objSslClientStream;
  1203. /*
  1204. SslClientStream sslstream = new SslClientStream(
  1205. socket.GetStream(),
  1206. nstream,
  1207. host,
  1208. false,
  1209. Mono.Security.Protocol.Tls.SecurityProtocolType.Ssl3| Mono.Security.Protocol.Tls.SecurityProtocolType.Tls);
  1210. sslstream.ServerCertValidationDelegate = new CertificateValidationCallback(ServerCertificateValidation);
  1211. this.in_Renamed = (System.IO.Stream) sslstream;
  1212. this.out_Renamed = (System.IO.Stream) sslstream;*/
  1213. }
  1214. catch (System.IO.IOException ioe)
  1215. {
  1216. this.nonTLSBackup = null;
  1217. throw new LdapException("Could not negotiate a secure connection", LdapException.CONNECT_ERROR, null, ioe);
  1218. }
  1219. catch (System.Exception uhe)
  1220. {
  1221. this.nonTLSBackup = null;
  1222. throw new LdapException("The host is unknown", LdapException.CONNECT_ERROR, null, uhe);
  1223. }
  1224. return ;
  1225. #endif
  1226. }
  1227. /*
  1228. * Stops TLS.
  1229. *
  1230. * StopTLS, in this package, assumes the caller has:
  1231. * 1) blocked writing (acquireWriteSemaphore).
  1232. * 2) checked that no messages are outstanding.
  1233. *
  1234. * StopTLS Needs to do the following:
  1235. * 1) close the current socket
  1236. * - This stops the reader thread
  1237. * - set STOP_READING flag on stopReaderMessageID so that
  1238. * the reader knows that the IOException is planned.
  1239. * 2) replace the current socket with nonTLSBackup,
  1240. * 3) and set nonTLSBackup to null;
  1241. * 4) reset input and outputstreams
  1242. * 5) start the reader thread by calling startReader
  1243. *
  1244. * Note: Sun's JSSE doesn't allow the nonTLSBackup socket to be
  1245. * used any more, even though autoclose was false: you get an IOException.
  1246. * IBM's JSSE hangs when you close the JSSE socket.
  1247. */
  1248. /* package */
  1249. internal void stopTLS()
  1250. {
  1251. try
  1252. {
  1253. this.stopReaderMessageID = Connection.STOP_READING;
  1254. this.out_Renamed.Close();
  1255. this.in_Renamed.Close();
  1256. // this.sock.Shutdown(SocketShutdown.Both);
  1257. // this.sock.Close();
  1258. waitForReader(null);
  1259. this.socket = this.nonTLSBackup;
  1260. this.in_Renamed = (System.IO.Stream) this.socket.GetStream();
  1261. this.out_Renamed = (System.IO.Stream) this.socket.GetStream();
  1262. // Allow the new reader to start
  1263. this.stopReaderMessageID = Connection.CONTINUE_READING;
  1264. }
  1265. catch (System.IO.IOException ioe)
  1266. {
  1267. throw new LdapException(ExceptionMessages.STOPTLS_ERROR, LdapException.CONNECT_ERROR, null, ioe);
  1268. }
  1269. finally
  1270. {
  1271. this.nonTLSBackup = null;
  1272. startReader();
  1273. }
  1274. return ;
  1275. }
  1276. ///TLS not supported in first release
  1277. internal Stream InputStream
  1278. {
  1279. get { return in_Renamed; }
  1280. }
  1281. internal Stream OutputStream
  1282. {
  1283. get { return out_Renamed; }
  1284. }
  1285. internal void ReplaceStreams(Stream newIn, Stream newOut)
  1286. {
  1287. // wait for reader to stop, see LdapConnection.Bind
  1288. waitForReader(null);
  1289. in_Renamed = newIn;
  1290. out_Renamed = newOut;
  1291. startReader();
  1292. }
  1293. public class ReaderThread
  1294. {
  1295. private void InitBlock(Connection enclosingInstance)
  1296. {
  1297. this.enclosingInstance = enclosingInstance;
  1298. }
  1299. private Connection enclosingInstance;
  1300. public Connection Enclosing_Instance
  1301. {
  1302. get
  1303. {
  1304. return enclosingInstance;
  1305. }
  1306. }
  1307. public ReaderThread(Connection enclosingInstance)
  1308. {
  1309. InitBlock(enclosingInstance);
  1310. return ;
  1311. }
  1312. /// <summary> This thread decodes and processes RfcLdapMessage's from the server.
  1313. ///
  1314. /// Note: This thread needs a graceful shutdown implementation.
  1315. /// </summary>
  1316. public virtual void Run()
  1317. {
  1318. System.String reason = "reader: thread stopping";
  1319. InterThreadException notify = null;
  1320. Message info = null;
  1321. System.IO.IOException ioex = null;
  1322. this.enclosingInstance.reader = System.Threading.Thread.CurrentThread;
  1323. // Enclosing_Instance.reader = SupportClass.ThreadClass.Current();
  1324. // Console.WriteLine("Inside run:" + this.enclosingInstance.reader.Name);
  1325. try
  1326. {
  1327. for (; ; )
  1328. {
  1329. // -------------------------------------------------------
  1330. // Decode an RfcLdapMessage directly from the socket.
  1331. // -------------------------------------------------------
  1332. Asn1Identifier asn1ID;
  1333. System.IO.Stream myIn;
  1334. /* get current value of in, keep value consistant
  1335. * though the loop, i.e. even during shutdown
  1336. */
  1337. myIn = this.enclosingInstance.in_Renamed;
  1338. if (myIn == null)
  1339. {
  1340. break;
  1341. }
  1342. asn1ID = new Asn1Identifier(myIn);
  1343. int tag = asn1ID.Tag;
  1344. if (asn1ID.Tag != Asn1Sequence.TAG)
  1345. {
  1346. continue; // loop looking for an RfcLdapMessage identifier
  1347. }
  1348. // Turn the message into an RfcMessage class
  1349. Asn1Length asn1Len = new Asn1Length(myIn);
  1350. RfcLdapMessage msg = new RfcLdapMessage(this.enclosingInstance.decoder, myIn, asn1Len.Length);
  1351. // ------------------------------------------------------------
  1352. // Process the decoded RfcLdapMessage.
  1353. // ------------------------------------------------------------
  1354. int msgId = msg.MessageID;
  1355. // Find the message which requested this response.
  1356. // It is possible to receive a response for a request which
  1357. // has been abandoned. If abandoned, throw it away
  1358. try
  1359. {
  1360. info = this.enclosingInstance.messages.findMessageById(msgId);
  1361. info.putReply(msg); // queue & wake up waiting thread
  1362. }
  1363. catch (System.FieldAccessException ex)
  1364. {
  1365. /*
  1366. * We get the NoSuchFieldException when we could not find
  1367. * a matching message id. First check to see if this is
  1368. * an unsolicited notification (msgID == 0). If it is not
  1369. * we throw it away. If it is we call any unsolicited
  1370. * listeners that might have been registered to listen for these
  1371. * messages.
  1372. */
  1373. /* Note the location of this code. We could have required
  1374. * that message ID 0 be just like other message ID's but
  1375. * since message ID 0 has to be treated specially we have
  1376. * a separate check for message ID 0. Also note that
  1377. * this test is after the regular message list has been
  1378. * checked for. We could have always checked the list
  1379. * of messages after checking if this is an unsolicited
  1380. * notification but that would have inefficient as
  1381. * message ID 0 is a rare event (as of this time).
  1382. */
  1383. if (msgId == 0)
  1384. {
  1385. // Notify any listeners that might have been registered
  1386. this.enclosingInstance.notifyAllUnsolicitedListeners(msg);
  1387. /*
  1388. * Was this a server shutdown unsolicited notification.
  1389. * IF so we quit. Actually calling the return will
  1390. * first transfer control to the finally clause which
  1391. * will do the necessary clean up.
  1392. */
  1393. if (this.enclosingInstance.unsolSvrShutDnNotification)
  1394. {
  1395. notify = new InterThreadException(ExceptionMessages.SERVER_SHUTDOWN_REQ, new System.Object[]{this.enclosingInstance.host, this.enclosingInstance.port}, LdapException.CONNECT_ERROR, null, null);
  1396. return ;
  1397. }
  1398. }
  1399. else
  1400. {
  1401. }
  1402. }
  1403. if ((this.enclosingInstance.stopReaderMessageID == msgId) || (this.enclosingInstance.stopReaderMessageID == Novell.Directory.Ldap.Connection.STOP_READING))
  1404. {
  1405. // Stop the reader Thread.
  1406. return ;
  1407. }
  1408. }
  1409. }
  1410. catch(ThreadAbortException tae)
  1411. {
  1412. // Abort has been called on reader
  1413. // before closing sockets, from shutdown
  1414. return;
  1415. }
  1416. #if TARGET_JVM
  1417. catch (ObjectDisposedException)
  1418. {
  1419. // we do not support Thread.Abort under java
  1420. // so we close the stream and the working thread
  1421. // catches ObjectDisposedException exception
  1422. return;
  1423. }
  1424. #endif
  1425. catch (System.IO.IOException ioe)
  1426. {
  1427. ioex = ioe;
  1428. if ((this.enclosingInstance.stopReaderMessageID != Novell.Directory.Ldap.Connection.STOP_READING) && this.enclosingInstance.clientActive)
  1429. {
  1430. // Connection lost waiting for results from host:port
  1431. notify = new InterThreadException(ExceptionMessages.CONNECTION_WAIT, new System.Object[]{this.enclosingInstance.host, this.enclosingInstance.port}, LdapException.CONNECT_ERROR, ioe, info);
  1432. }
  1433. // The connection is no good, don't use it any more
  1434. this.enclosingInstance.in_Renamed = null;
  1435. this.enclosingInstance.out_Renamed = null;
  1436. }
  1437. finally
  1438. {
  1439. /*
  1440. * There can be four states that the reader can be in at this point:
  1441. * 1) We are starting TLS and will be restarting the reader
  1442. * after we have negotiated TLS.
  1443. * - Indicated by whether stopReaderMessageID does not
  1444. * equal CONTINUE_READING.
  1445. * - Don't call Shutdown.
  1446. * 2) We are stoping TLS and will be restarting after TLS is
  1447. * stopped.
  1448. * - Indicated by an IOException AND stopReaderMessageID equals
  1449. * STOP_READING - in which case notify will be null.
  1450. * - Don't call Shutdown
  1451. * 3) We receive a Server Shutdown notification.
  1452. * - Indicated by messageID equal to 0.
  1453. * - call Shutdown.
  1454. * 4) Another error occured
  1455. * - Indicated by an IOException AND notify is not NULL
  1456. * - call Shutdown.
  1457. */
  1458. if ((!this.enclosingInstance.clientActive) || (notify != null))
  1459. {
  1460. //#3 & 4
  1461. this.enclosingInstance.shutdown(reason, 0, notify);
  1462. }
  1463. else
  1464. {
  1465. this.enclosingInstance.stopReaderMessageID = Novell.Directory.Ldap.Connection.CONTINUE_READING;
  1466. }
  1467. }
  1468. this.enclosingInstance.deadReaderException = ioex;
  1469. this.enclosingInstance.deadReader = this.enclosingInstance.reader;
  1470. this.enclosingInstance.reader = null;
  1471. return ;
  1472. }
  1473. } // End class ReaderThread
  1474. /// <summary>Add the specific object to the list of listeners that want to be
  1475. /// notified when an unsolicited notification is received.
  1476. /// </summary>
  1477. /* package */
  1478. internal void AddUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
  1479. {
  1480. unsolicitedListeners.Add(listener);
  1481. return ;
  1482. }
  1483. /// <summary>Remove the specific object from current list of listeners</summary>
  1484. /* package */
  1485. internal void RemoveUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
  1486. {
  1487. SupportClass.VectorRemoveElement(unsolicitedListeners, listener);
  1488. return ;
  1489. }
  1490. /// <summary>Inner class defined so that we can spawn off each unsolicited
  1491. /// listener as a seperate thread. We did not want to call the
  1492. /// unsolicited listener method directly as this would have tied up our
  1493. /// deamon listener thread in the applications unsolicited listener method.
  1494. /// Since we do not know what the application unsolicited listener
  1495. /// might be doing and how long it will take to process the uncoslicited
  1496. /// notification. We use this class to spawn off the unsolicited
  1497. /// notification as a separate thread
  1498. /// </summary>
  1499. private class UnsolicitedListenerThread:SupportClass.ThreadClass
  1500. {
  1501. private void InitBlock(Connection enclosingInstance)
  1502. {
  1503. this.enclosingInstance = enclosingInstance;
  1504. }
  1505. private Con

Large files files are truncated, but you can click here to view the full file