PageRenderTime 64ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/otp.net/Otp/OtpConnection.cs

https://github.com/gebi/jungerl
C# | 500 lines | 141 code | 41 blank | 318 comment | 10 complexity | fbafeefd9abd28f384766fde235af46b MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, AGPL-1.0
  1. /*``The contents of this file are subject to the Erlang Public License,
  2. * Version 1.1, (the "License"); you may not use this file except in
  3. * compliance with the License. You should have received a copy of the
  4. * Erlang Public License along with this software. If not, it can be
  5. * retrieved via the world wide web at http://www.erlang.org/.
  6. *
  7. * Software distributed under the License is distributed on an "AS IS"
  8. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  9. * the License for the specific language governing rights and limitations
  10. * under the License.
  11. *
  12. * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
  13. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
  14. * AB. All Rights Reserved.''
  15. *
  16. * Converted from Java to C# by Vlad Dumitrescu (vlad_Dumitrescu@hotmail.com)
  17. */
  18. using System;
  19. using System.Diagnostics;
  20. namespace Otp
  21. {
  22. /*
  23. * Maintains a connection between a C# process and a remote Erlang,
  24. * C# or C node. The object maintains connection state and allows
  25. * data to be sent to and received from the peer.
  26. *
  27. * <p> Once a connection is established between the local node and a
  28. * remote node, the connection object can be used to send and receive
  29. * messages between the nodes and make rpc calls (assuming that the
  30. * remote node is a real Erlang node).
  31. *
  32. * <p> The various receive methods are all blocking and will return
  33. * only when a valid message has been received or an exception is
  34. * raised.
  35. *
  36. * <p> If an exception occurs in any of the methods in this class, the
  37. * connection will be closed and must be explicitely reopened in order
  38. * to resume communication with the peer.
  39. *
  40. * <p> It is not possible to create an instance of this class
  41. * directly. OtpConnection objects are returned by {@link
  42. * OtpSelf#connect(OtpPeer) OtpSelf.connect()} and {@link
  43. * OtpSelf#accept() OtpSelf.accept()}.
  44. **/
  45. public class OtpConnection:AbstractConnection
  46. {
  47. protected internal OtpSelf _self;
  48. protected internal GenericQueue queue; // messages get delivered here
  49. /*
  50. * Accept an incoming connection from a remote node. Used by {@link
  51. * OtpSelf#accept() OtpSelf.accept()} to create a connection
  52. * based on data received when handshaking with the peer node, when
  53. * the remote node is the connection intitiator.
  54. *
  55. * @exception C#.io.IOException if it was not possible to connect to the peer.
  56. *
  57. * @exception OtpAuthException if handshake resulted in an authentication error
  58. */
  59. // package scope
  60. internal OtpConnection(OtpSelf self, System.Net.Sockets.TcpClient s):base(self, s)
  61. {
  62. this._self = self;
  63. this.queue = new GenericQueue();
  64. System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(Start));
  65. t.IsBackground = true;
  66. t.Name = "connection "+self.node()+" | "+s.ToString();
  67. t.Start();
  68. }
  69. /*
  70. * Intiate and open a connection to a remote node.
  71. *
  72. * @exception C#.io.IOException if it was not possible to connect to the peer.
  73. *
  74. * @exception OtpAuthException if handshake resulted in an authentication error.
  75. */
  76. // package scope
  77. internal OtpConnection(OtpSelf self, OtpPeer other):base(self, other)
  78. {
  79. this._self = self;
  80. this.queue = new GenericQueue();
  81. System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(Start));
  82. t.IsBackground = true;
  83. t.Name = "connection2 "+self.node()+" -> "+other.node();
  84. t.Start();
  85. }
  86. public override void deliver(System.Exception e)
  87. {
  88. queue.put(e);
  89. }
  90. public override void deliver(OtpMsg msg)
  91. {
  92. queue.put(msg);
  93. }
  94. /*
  95. * Get information about the node at the peer end of this
  96. * connection.
  97. *
  98. * @return the {@link OtpPeer Node} representing the peer node.
  99. **/
  100. public virtual OtpPeer getPeer()
  101. {
  102. return peer;
  103. }
  104. /*
  105. * Get information about the node at the local end of this
  106. * connection.
  107. *
  108. * @return the {@link OtpSelf Node} representing the local node.
  109. **/
  110. public virtual new OtpSelf self()
  111. {
  112. return _self;
  113. }
  114. /*
  115. * Return the number of messages currently waiting in the receive
  116. * queue for this connection.
  117. */
  118. public virtual int msgCount()
  119. {
  120. return queue.getCount();
  121. }
  122. /*
  123. * Receive an RPC reply from the remote Erlang node. This
  124. * convenience function receives a message from the remote node, and
  125. * expects it to have the following format:
  126. *
  127. * <pre>
  128. * {rex, Term}
  129. * </pre>
  130. *
  131. * @return the second element of the tuple if the received message
  132. * is a two-tuple, otherwise null. No further error checking is
  133. * performed.
  134. *
  135. * @exception C#.io.IOException if the connection is not active or
  136. * a communication error occurs.
  137. *
  138. * @exception Erlang.Exit if an exit signal is
  139. * received from a process on the peer node.
  140. *
  141. * @exception OtpAuthException if the remote node
  142. * sends a message containing an invalid cookie.
  143. **/
  144. public virtual Erlang.Object receiveRPC()
  145. {
  146. Erlang.Object msg = receive();
  147. Debug.WriteLine("receiveRPC: " + msg.ToString());
  148. return AbstractConnection.decodeRPC(msg);
  149. }
  150. /*
  151. * Receive a message from a remote process. This method blocks
  152. * until a valid message is received or an exception is raised.
  153. *
  154. * <p> If the remote node sends a message that cannot be decoded
  155. * properly, the connection is closed and the method throws an
  156. * exception.
  157. *
  158. * @return an object containing a single Erlang term.
  159. *
  160. * @exception C#.io.IOException if the connection is not active or
  161. * a communication error occurs.
  162. *
  163. * @exception Erlang.Exit if an exit signal is
  164. * received from a process on the peer node.
  165. *
  166. * @exception OtpAuthException if the remote node
  167. * sends a message containing an invalid cookie.
  168. **/
  169. public virtual Erlang.Object receive()
  170. {
  171. return receive(-1);
  172. }
  173. /*
  174. * Receive a message from a remote process. This method blocks at
  175. * most for the specified time, until a valid message is received or
  176. * an exception is raised.
  177. *
  178. * <p> If the remote node sends a message that cannot be decoded
  179. * properly, the connection is closed and the method throws an
  180. * exception.
  181. *
  182. * @param timeout the time in milliseconds that this operation will
  183. * block. Specify 0 to poll the queue.
  184. *
  185. * @return an object containing a single Erlang term.
  186. *
  187. * @exception C#.io.IOException if the connection is not active or
  188. * a communication error occurs.
  189. *
  190. * @exception Erlang.Exit if an exit signal is
  191. * received from a process on the peer node.
  192. *
  193. * @exception OtpAuthException if the remote node
  194. * sends a message containing an invalid cookie.
  195. *
  196. * @exception InterruptedException if no message if the method
  197. * times out before a message becomes available.
  198. **/
  199. public virtual Erlang.Object receive(long timeout)
  200. {
  201. try
  202. {
  203. OtpMsg msg = receiveMsg(timeout);
  204. return msg == null ? null : msg.getMsg();
  205. }
  206. catch (Erlang.Exception e)
  207. {
  208. close();
  209. throw new System.IO.IOException(e.Message);
  210. }
  211. }
  212. /*
  213. * Receive a raw (still encoded) message from a remote process.
  214. * This message blocks until a valid message is received or an
  215. * exception is raised.
  216. *
  217. * <p> If the remote node sends a message that cannot be decoded
  218. * properly, the connection is closed and the method throws an
  219. * exception.
  220. *
  221. * @return an object containing a raw (still encoded) Erlang term.
  222. *
  223. * @exception C#.io.IOException if the connection is not active or
  224. * a communication error occurs.
  225. *
  226. * @exception Erlang.Exit if an exit signal is received from a
  227. * process on the peer node, or if the connection is lost for any
  228. * reason.
  229. *
  230. * @exception OtpAuthException if the remote node
  231. * sends a message containing an invalid cookie.
  232. **/
  233. public virtual OtpInputStream receiveBuf()
  234. {
  235. return receiveBuf(-1);
  236. }
  237. /*
  238. * Receive a raw (still encoded) message from a remote process. This
  239. * message blocks at most for the specified time until a valid
  240. * message is received or an exception is raised.
  241. *
  242. * <p> If the remote node sends a message that cannot be decoded
  243. * properly, the connection is closed and the method throws an
  244. * exception.
  245. *
  246. * @param timeout the time in milliseconds that this operation will
  247. * block. Specify 0 to poll the queue.
  248. *
  249. * @return an object containing a raw (still encoded) Erlang term.
  250. *
  251. * @exception C#.io.IOException if the connection is not active or
  252. * a communication error occurs.
  253. *
  254. * @exception Erlang.Exit if an exit signal is received from a
  255. * process on the peer node, or if the connection is lost for any
  256. * reason.
  257. *
  258. * @exception OtpAuthException if the remote node
  259. * sends a message containing an invalid cookie.
  260. *
  261. * @exception InterruptedException if no message if the method
  262. * times out before a message becomes available.
  263. **/
  264. public virtual OtpInputStream receiveBuf(long timeout)
  265. {
  266. OtpMsg str = receiveMsg(timeout);
  267. return str != null ? str.getMsgBuf() : null;
  268. }
  269. /*
  270. * Receive a messge complete with sender and recipient information.
  271. *
  272. * @return an {@link OtpMsg OtpMsg} containing the header
  273. * information about the sender and recipient, as well as the actual
  274. * message contents.
  275. *
  276. * @exception C#.io.IOException if the connection is not active or
  277. * a communication error occurs.
  278. *
  279. * @exception Erlang.Exit if an exit signal is received from a
  280. * process on the peer node, or if the connection is lost for any
  281. * reason.
  282. *
  283. * @exception OtpAuthException if the remote node
  284. * sends a message containing an invalid cookie.
  285. **/
  286. public virtual OtpMsg receiveMsg()
  287. {
  288. return receiveMsg(-1);
  289. }
  290. /*
  291. * Receive a messge complete with sender and recipient information.
  292. * This method blocks at most for the specified time.
  293. *
  294. * @param timeout the time in milliseconds that this operation will
  295. * block. Specify 0 to poll the queue.
  296. *
  297. * @return an {@link OtpMsg OtpMsg} containing the header
  298. * information about the sender and recipient, as well as the actual
  299. * message contents.
  300. *
  301. * @exception C#.io.IOException if the connection is not active or
  302. * a communication error occurs.
  303. *
  304. * @exception Erlang.Exit if an exit signal is received from a
  305. * process on the peer node, or if the connection is lost for any
  306. * reason.
  307. *
  308. * @exception OtpAuthException if the remote node
  309. * sends a message containing an invalid cookie.
  310. *
  311. * @exception InterruptedException if no message if the method
  312. * times out before a message becomes available.
  313. **/
  314. public virtual OtpMsg receiveMsg(long timeout)
  315. {
  316. System.Object o = timeout == -1 ? queue.get() : queue.get(timeout);
  317. if (o is OtpMsg)
  318. {
  319. return ((OtpMsg) o);
  320. }
  321. else if (o is System.IO.IOException)
  322. {
  323. throw (System.IO.IOException) o;
  324. }
  325. else if (o is Erlang.Exit)
  326. {
  327. throw (Erlang.Exit) o;
  328. }
  329. else if (o is OtpAuthException)
  330. {
  331. throw (OtpAuthException) o;
  332. }
  333. return null;
  334. }
  335. /*
  336. * Send a message to a process on a remote node.
  337. *
  338. * @param dest the Erlang PID of the remote process.
  339. * @param msg the message to send.
  340. * @exception C#.io.IOException if the connection is not active
  341. * or a communication error occurs.
  342. **/
  343. public virtual void send(Erlang.Pid dest, Erlang.Object msg)
  344. {
  345. // encode and send the message
  346. base.sendBuf(this._self.pid(), dest, new OtpOutputStream(msg));
  347. }
  348. /*
  349. * Send a message to a named process on a remote node.
  350. *
  351. * @param dest the name of the remote process.
  352. * @param msg the message to send.
  353. *
  354. * @exception C#.io.IOException if the connection is not active or
  355. * a communication error occurs.
  356. **/
  357. public virtual void send(System.String dest, Erlang.Object msg)
  358. {
  359. // encode and send the message
  360. base.sendBuf(this._self.pid(), dest, new OtpOutputStream(msg));
  361. }
  362. /*
  363. * Send a pre-encoded message to a named process on a remote node.
  364. *
  365. * @param dest the name of the remote process.
  366. * @param payload the encoded message to send.
  367. *
  368. * @exception C#.io.IOException if the connection is not active or
  369. * a communication error occurs.
  370. **/
  371. public virtual void sendBuf(System.String dest, OtpOutputStream payload)
  372. {
  373. base.sendBuf(this._self.pid(), dest, payload);
  374. }
  375. /*
  376. * Send a pre-encoded message to a process on a remote node.
  377. *
  378. * @param dest the Erlang PID of the remote process.
  379. * @param msg the encoded message to send.
  380. *
  381. * @exception C#.io.IOException if the connection is not active
  382. * or a communication error occurs.
  383. **/
  384. public virtual void sendBuf(Erlang.Pid dest, OtpOutputStream payload)
  385. {
  386. base.sendBuf(this._self.pid(), dest, payload);
  387. }
  388. /*
  389. * Send an RPC request to the remote Erlang node. This convenience
  390. * function creates the following message and sends it to 'rex' on
  391. * the remote node:
  392. *
  393. * <pre>
  394. * { self, { call, Mod, Fun, Args, user }}
  395. * </pre>
  396. *
  397. * <p> Note that this method has unpredicatble results if the remote
  398. * node is not an Erlang node. </p>
  399. *
  400. * @param mod the name of the Erlang module containing the function to be called.
  401. * @param fun the name of the function to call.
  402. * @param args an array of Erlang terms, to be used as arguments to the function.
  403. *
  404. * @exception C#.io.IOException if the connection is not active
  405. * or a communication error occurs.
  406. **/
  407. public virtual void sendRPC(System.String mod, System.String fun, Erlang.Object[] args)
  408. {
  409. sendRPC(mod, fun, new Erlang.List(args));
  410. }
  411. public virtual void sendRPC(System.String mod, System.String fun, Erlang.List args)
  412. {
  413. sendRPC(_self.pid(), mod, fun, args);
  414. }
  415. /*
  416. * Create a link between the local node and the specified process on
  417. * the remote node. If the link is still active when the remote
  418. * process terminates, an exit signal will be sent to this
  419. * connection. Use {@link #unlink unlink()} to remove the link.
  420. *
  421. * @param dest the Erlang PID of the remote process.
  422. *
  423. * @exception C#.io.IOException if the connection is not active
  424. * or a communication error occurs.
  425. **/
  426. public virtual void link(Erlang.Pid dest)
  427. {
  428. base.sendLink(this._self.pid(), dest);
  429. }
  430. /*
  431. * Remove a link between the local node and the specified process on
  432. * the remote node. This method deactivates links created with
  433. * {@link #link link()}.
  434. *
  435. * @param dest the Erlang PID of the remote process.
  436. *
  437. * @exception C#.io.IOException if the connection is not active or
  438. * a communication error occurs.
  439. **/
  440. public virtual void unlink(Erlang.Pid dest)
  441. {
  442. base.sendUnlink(this._self.pid(), dest);
  443. }
  444. /*
  445. * Send an exit signal to a remote process.
  446. *
  447. * @param dest the Erlang PID of the remote process.
  448. * @param reason a string describing the exit reason.
  449. *
  450. * @exception C#.io.IOException if the connection is not active or
  451. * a communication error occurs.
  452. **/
  453. public virtual void exit(Erlang.Pid dest, System.String reason)
  454. {
  455. base.sendExit2(this._self.pid(), dest, reason);
  456. }
  457. }
  458. }