Transport.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. // This code is derived from jcifs smb client library <jcifs at samba dot org>
  2. // Ported by J. Arturo <webmaster at komodosoft dot net>
  3. //
  4. // This library is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU Lesser General Public
  6. // License as published by the Free Software Foundation; either
  7. // version 2.1 of the License, or (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. // Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public
  15. // License along with this library; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. using System;
  18. using System.IO;
  19. using SharpCifs.Smb;
  20. using SharpCifs.Util.Sharpen;
  21. namespace SharpCifs.Util.Transport
  22. {
  23. /// <summary>
  24. /// This class simplifies communication for protocols that support
  25. /// multiplexing requests.
  26. /// </summary>
  27. /// <remarks>
  28. /// This class simplifies communication for protocols that support
  29. /// multiplexing requests. It encapsulates a stream and some protocol
  30. /// knowledge (provided by a concrete subclass) so that connecting,
  31. /// disconnecting, sending, and receiving can be syncronized
  32. /// properly. Apparatus is provided to send and receive requests
  33. /// concurrently.
  34. /// </remarks>
  35. public abstract class Transport : IRunnable
  36. {
  37. internal static int Id;
  38. //internal static LogStream log = LogStream.GetInstance();
  39. public LogStream Log
  40. {
  41. get
  42. {
  43. return LogStream.GetInstance();
  44. }
  45. }
  46. /// <exception cref="System.IO.IOException"></exception>
  47. public static int Readn(InputStream @in, byte[] b, int off, int len)
  48. {
  49. int i = 0;
  50. int n = -5;
  51. while (i < len)
  52. {
  53. n = @in.Read(b, off + i, len - i);
  54. if (n <= 0)
  55. {
  56. break;
  57. }
  58. i += n;
  59. }
  60. return i;
  61. }
  62. internal int State;
  63. internal string Name = "Transport" + Id++;
  64. internal Thread Thread;
  65. internal TransportException Te;
  66. protected internal Hashtable ResponseMap = new Hashtable();
  67. /// <exception cref="System.IO.IOException"></exception>
  68. protected internal abstract void MakeKey(ServerMessageBlock request);
  69. /// <exception cref="System.IO.IOException"></exception>
  70. protected internal abstract ServerMessageBlock PeekKey();
  71. /// <exception cref="System.IO.IOException"></exception>
  72. protected internal abstract void DoSend(ServerMessageBlock request);
  73. /// <exception cref="System.IO.IOException"></exception>
  74. protected internal abstract void DoRecv(Response response);
  75. /// <exception cref="System.IO.IOException"></exception>
  76. protected internal abstract void DoSkip();
  77. /// <exception cref="System.IO.IOException"></exception>
  78. public virtual void Sendrecv(ServerMessageBlock request, Response response, long timeout)
  79. {
  80. lock (this)
  81. {
  82. MakeKey(request);
  83. response.IsReceived = false;
  84. try
  85. {
  86. ResponseMap.Put(request, response);
  87. DoSend(request);
  88. response.Expiration = Runtime.CurrentTimeMillis() + timeout;
  89. while (!response.IsReceived)
  90. {
  91. Runtime.Wait(this, timeout);
  92. timeout = response.Expiration - Runtime.CurrentTimeMillis();
  93. if (timeout <= 0)
  94. {
  95. throw new TransportException(Name + " timedout waiting for response to " + request
  96. );
  97. }
  98. }
  99. }
  100. catch (IOException ioe)
  101. {
  102. if (Log.Level > 2)
  103. {
  104. Runtime.PrintStackTrace(ioe, Log);
  105. }
  106. try
  107. {
  108. Disconnect(true);
  109. }
  110. catch (IOException ioe2)
  111. {
  112. Runtime.PrintStackTrace(ioe2, Log);
  113. }
  114. throw;
  115. }
  116. catch (Exception ie)
  117. {
  118. throw new TransportException(ie);
  119. }
  120. finally
  121. {
  122. //Sharpen.Collections.Remove(response_map, request);
  123. ResponseMap.Remove(request);
  124. }
  125. }
  126. }
  127. private void Loop()
  128. {
  129. while (Thread == Thread.CurrentThread())
  130. {
  131. try
  132. {
  133. ServerMessageBlock key = PeekKey();
  134. if (key == null)
  135. {
  136. throw new IOException("end of stream");
  137. }
  138. lock (this)
  139. {
  140. Response response = (Response)ResponseMap.Get(key);
  141. if (response == null)
  142. {
  143. if (Log.Level >= 4)
  144. {
  145. Log.WriteLine("Invalid key, skipping message");
  146. }
  147. DoSkip();
  148. }
  149. else
  150. {
  151. DoRecv(response);
  152. response.IsReceived = true;
  153. Runtime.NotifyAll(this);
  154. }
  155. }
  156. }
  157. catch (Exception ex)
  158. {
  159. string msg = ex.Message;
  160. bool timeout = msg != null && msg.Equals("Read timed out");
  161. bool hard = timeout == false;
  162. if (!timeout && Log.Level >= 3)
  163. {
  164. Runtime.PrintStackTrace(ex, Log);
  165. }
  166. try
  167. {
  168. Disconnect(hard);
  169. }
  170. catch (IOException ioe)
  171. {
  172. Runtime.PrintStackTrace(ioe, Log);
  173. }
  174. }
  175. }
  176. }
  177. /// <exception cref="System.Exception"></exception>
  178. protected internal abstract void DoConnect();
  179. /// <exception cref="System.IO.IOException"></exception>
  180. protected internal abstract void DoDisconnect(bool hard);
  181. /// <exception cref="SharpCifs.Util.Transport.TransportException"></exception>
  182. public virtual void Connect(long timeout)
  183. {
  184. lock (this)
  185. {
  186. try
  187. {
  188. switch (State)
  189. {
  190. case 0:
  191. {
  192. break;
  193. }
  194. case 3:
  195. {
  196. return;
  197. }
  198. case 4:
  199. {
  200. // already connected
  201. State = 0;
  202. throw new TransportException("Connection in error", Te);
  203. }
  204. default:
  205. {
  206. //TransportException te = new TransportException("Invalid state: " + state);
  207. State = 0;
  208. throw new TransportException("Invalid state: " + State);
  209. }
  210. }
  211. State = 1;
  212. Te = null;
  213. Thread = new Thread(this);
  214. Thread.SetDaemon(true);
  215. lock (Thread)
  216. {
  217. Thread.Start();
  218. Runtime.Wait(Thread, timeout);
  219. switch (State)
  220. {
  221. case 1:
  222. {
  223. State = 0;
  224. Thread = null;
  225. throw new TransportException("Connection timeout");
  226. }
  227. case 2:
  228. {
  229. if (Te != null)
  230. {
  231. State = 4;
  232. Thread = null;
  233. throw Te;
  234. }
  235. State = 3;
  236. return;
  237. }
  238. }
  239. }
  240. }
  241. catch (Exception ie)
  242. {
  243. State = 0;
  244. Thread = null;
  245. throw new TransportException(ie);
  246. }
  247. finally
  248. {
  249. if (State != 0 && State != 3 && State != 4)
  250. {
  251. if (Log.Level >= 1)
  252. {
  253. Log.WriteLine("Invalid state: " + State);
  254. }
  255. State = 0;
  256. Thread = null;
  257. }
  258. }
  259. }
  260. }
  261. /// <exception cref="System.IO.IOException"></exception>
  262. public virtual void Disconnect(bool hard)
  263. {
  264. if (hard)
  265. {
  266. IOException ioe = null;
  267. switch (State)
  268. {
  269. case 0:
  270. {
  271. return;
  272. }
  273. case 2:
  274. {
  275. hard = true;
  276. goto case 3;
  277. }
  278. case 3:
  279. {
  280. if (ResponseMap.Count != 0 && !hard)
  281. {
  282. break;
  283. }
  284. try
  285. {
  286. DoDisconnect(hard);
  287. }
  288. catch (IOException ioe0)
  289. {
  290. ioe = ioe0;
  291. }
  292. goto case 4;
  293. }
  294. case 4:
  295. {
  296. Thread = null;
  297. State = 0;
  298. break;
  299. }
  300. default:
  301. {
  302. if (Log.Level >= 1)
  303. {
  304. Log.WriteLine("Invalid state: " + State);
  305. }
  306. Thread = null;
  307. State = 0;
  308. break;
  309. }
  310. }
  311. if (ioe != null)
  312. {
  313. throw ioe;
  314. }
  315. return;
  316. }
  317. lock (this)
  318. {
  319. IOException ioe = null;
  320. switch (State)
  321. {
  322. case 0:
  323. {
  324. return;
  325. }
  326. case 2:
  327. {
  328. hard = true;
  329. goto case 3;
  330. }
  331. case 3:
  332. {
  333. if (ResponseMap.Count != 0 && !hard)
  334. {
  335. break;
  336. }
  337. try
  338. {
  339. DoDisconnect(hard);
  340. }
  341. catch (IOException ioe0)
  342. {
  343. ioe = ioe0;
  344. }
  345. goto case 4;
  346. }
  347. case 4:
  348. {
  349. Thread = null;
  350. State = 0;
  351. break;
  352. }
  353. default:
  354. {
  355. if (Log.Level >= 1)
  356. {
  357. Log.WriteLine("Invalid state: " + State);
  358. }
  359. Thread = null;
  360. State = 0;
  361. break;
  362. }
  363. }
  364. if (ioe != null)
  365. {
  366. throw ioe;
  367. }
  368. }
  369. }
  370. public virtual void Run()
  371. {
  372. Thread runThread = Thread.CurrentThread();
  373. Exception ex0 = null;
  374. try
  375. {
  376. DoConnect();
  377. }
  378. catch (Exception ex)
  379. {
  380. ex0 = ex;
  381. // Defer to below where we're locked
  382. return;
  383. }
  384. finally
  385. {
  386. lock (runThread)
  387. {
  388. if (runThread != Thread)
  389. {
  390. if (ex0 != null)
  391. {
  392. if (Log.Level >= 2)
  393. {
  394. Runtime.PrintStackTrace(ex0, Log);
  395. }
  396. }
  397. //return;
  398. }
  399. if (ex0 != null)
  400. {
  401. Te = new TransportException(ex0);
  402. }
  403. State = 2;
  404. // run connected
  405. Runtime.Notify(runThread);
  406. }
  407. }
  408. Loop();
  409. }
  410. public override string ToString()
  411. {
  412. return Name;
  413. }
  414. }
  415. }