PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/ZmqSocketTest.as

https://gitlab.com/BGCX261/zmqsocket-as-svn-to-git
ActionScript | 394 lines | 267 code | 59 blank | 68 comment | 42 complexity | 750d0f3cc9f0921dfb272517fa231c8a MD5 | raw file
  1. /*
  2. Copyright (c) 2011 by Artur Brugeman
  3. License: GNU GPL v3
  4. */
  5. package
  6. {
  7. import flash.errors.*;
  8. import flash.events.*;
  9. import flash.net.Socket;
  10. import flash.utils.ByteArray;
  11. public class ZmqSocket extends EventDispatcher
  12. {
  13. // Encapsulated tcp socket.
  14. private var socket: Socket = null;
  15. // Identity of socket, null if anonymous.
  16. private var identity: String = null;
  17. // Identity of peer, null if anonymous.
  18. private var peerIdentity: String = null;
  19. // True if received peer's identity.
  20. private var connected: Boolean = false;
  21. // FIFO queue of received messages
  22. private var queue: Array = null;
  23. // States that there are more frames of last message
  24. private var more: Boolean = false;
  25. // Current message, stored here until all frames are read
  26. private var current: Array = null;
  27. // Number of bytes required for current decoder
  28. // 1 is value required by frameLengthDecoder
  29. private var decoderMinBytes: int = 1;
  30. // When decoderMinBytes are available, they are read
  31. // and decoder is called. The decoder returns pointer
  32. // to next decoder, and modifies decoderMinBytes accordingly.
  33. private var decoder: Function = frameLengthDecoder;
  34. // Length of current frame
  35. private var frameLength: uint = 0;
  36. // Flags of current frame
  37. private var frameFlags: uint = 0;
  38. // Dispatched events
  39. // Dispatched when peer's identity is received
  40. public static var OPEN: String = "zmq_socket_open";
  41. // Dispatched when a message is received
  42. public static var MESSAGE: String = "zmq_socket_message";
  43. // Other dispatched events are CLOSE, SECURITY_ERROR and IO_ERROR
  44. // Constructor might throw a security exception.
  45. public function ZmqSocket (identity: String = null)
  46. {
  47. super ();
  48. // FIXME identity must be < 256 bytes
  49. this.identity = identity;
  50. queue = new Array;
  51. socket = new Socket;
  52. // These are handled to send identity and read messages.
  53. socket.addEventListener (Event.CONNECT, connectHandler);
  54. socket.addEventListener (ProgressEvent.SOCKET_DATA, socketDataHandler);
  55. // These are propagated upwards.
  56. socket.addEventListener (Event.CLOSE,
  57. function (e: Event) { dispatchEvent (e.clone ()); });
  58. socket.addEventListener (SecurityErrorEvent.SECURITY_ERROR,
  59. function (e: SecurityErrorEvent) { dispatchEvent (e.clone ()); });
  60. socket.addEventListener (IOErrorEvent.IO_ERROR,
  61. function (e: IOErrorEvent) { dispatchEvent (e.clone ()); });
  62. }
  63. // Add event listeners before connecting.
  64. public function connect (host: String, port: int)
  65. {
  66. socket.connect (host, port);
  67. }
  68. // Call to close TCP connection.
  69. public function close ()
  70. {
  71. socket.close ();
  72. }
  73. // Checks whether there are messages available for reading.
  74. public function available (): uint
  75. {
  76. return queue.length;
  77. }
  78. // Read a message consisting of String-s, returns null if no messages available.
  79. // Doesn't block.
  80. public function recv (): Array
  81. {
  82. if (queue.length > 0)
  83. {
  84. var bin: Array = queue.shift ();
  85. var str: Array = new Array;
  86. while (bin.length > 0)
  87. {
  88. var frame: ByteArray = bin.shift ();
  89. if (frame != null)
  90. str.push (frame.readUTFBytes (frame.length));
  91. else
  92. str.push ("");
  93. }
  94. return str;
  95. }
  96. return null;
  97. }
  98. // Read a message consisting of ByteArray-s, returns null if no
  99. // messages available. Doesn't block.
  100. public function recvBin (): Array
  101. {
  102. if (queue.length > 0)
  103. return queue.shift ();
  104. return null;
  105. }
  106. // Send a message consisting of String-s, triggets IO_ERROR event if
  107. // socket is not connected or msg == null.
  108. public function send (msg: Array): void
  109. {
  110. if (!canSend (msg))
  111. return;
  112. while (msg.length > 0)
  113. {
  114. var frame: String = msg.shift ();
  115. writeFrame (frame, msg.length > 0);
  116. }
  117. }
  118. // Send a message consisting of ByteArray-s, triggets IO_ERROR event if
  119. // socket is not connected or msg == null.
  120. public function sendBin (msg: Array): void
  121. {
  122. if (!canSend (msg))
  123. return;
  124. while (msg.length > 0)
  125. {
  126. var frame: ByteArray = msg.shift ();
  127. writeFrameBin (frame, msg.length > 0);
  128. }
  129. }
  130. private function canSend (msg: Array): Boolean
  131. {
  132. if (!connected)
  133. {
  134. dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, false, false,
  135. "Socket is not connected yet"));
  136. return false;
  137. }
  138. if (msg == null)
  139. {
  140. dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, false, false,
  141. "Input message is NULL"));
  142. return false;
  143. }
  144. return true;
  145. }
  146. private function writeFrame (frame: String, more: Boolean = false): void
  147. {
  148. var buf: ByteArray = new ByteArray;
  149. if (frame != null && frame.length > 0)
  150. buf.writeUTFBytes (frame);
  151. writeFrameBin (buf, more);
  152. }
  153. private function writeFrameBin (frame: ByteArray, more: Boolean = false): void
  154. {
  155. // Length
  156. var len: int = frame.length + 1;
  157. if (len < 255)
  158. {
  159. socket.writeByte (len);
  160. }
  161. else
  162. {
  163. // Flags 64-bit length
  164. socket.writeByte (0xFF);
  165. // Leading 32 bits set to 0
  166. socket.writeUnsignedInt (0);
  167. // Least significant 32 bits are our length
  168. socket.writeUnsignedInt (len);
  169. }
  170. // Flags
  171. if (more)
  172. socket.writeByte (1);
  173. else
  174. socket.writeByte (0);
  175. // Data
  176. if (frame.length > 0)
  177. socket.writeBytes (frame);
  178. socket.flush ();
  179. }
  180. private function readNextFrame (): Boolean
  181. {
  182. // Main decoding cycle
  183. while (socket.bytesAvailable >= decoderMinBytes)
  184. {
  185. // Read bytes required by current decoder
  186. var bytes: ByteArray = new ByteArray;
  187. socket.readBytes (bytes, 0, decoderMinBytes);
  188. // Decode.
  189. decoder = decoder (bytes);
  190. // Returned NULL means a new frame was read.
  191. if (decoder == null)
  192. {
  193. // Set initial decoder to read the next frame.
  194. decoderMinBytes = 1;
  195. decoder = frameLengthDecoder;
  196. // True means frame was read.
  197. return true;
  198. }
  199. }
  200. // No frame was read.
  201. return false;
  202. }
  203. private function frameLengthDecoder (bytes: ByteArray): Function
  204. {
  205. // First byte is length.
  206. frameLength = bytes.readUnsignedByte ();
  207. // Length == 0 is bad
  208. if (frameLength == 0)
  209. {
  210. dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, false, false,
  211. "Socket is sending bad length"));
  212. socket.close ();
  213. return null;
  214. }
  215. // Indicates 64-bit length
  216. if (frameLength == 0xFF)
  217. {
  218. decoderMinBytes = 8;
  219. return frameBigLengthDecoder;
  220. }
  221. return frameFlagsDecoder;
  222. }
  223. private function frameBigLengthDecoder (bytes: ByteArray): Function
  224. {
  225. frameLength = bytes.readUnsignedInt ();
  226. // If significant 32-bits are not 0, means message
  227. // size exceeds maximum, and we close connection.
  228. if (frameLength != 0)
  229. {
  230. dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, false, false,
  231. "Incoming message size is too big"));
  232. socket.close ();
  233. return null;
  234. }
  235. // Least significant 32 bits are the length.
  236. frameLength = bytes.readUnsignedInt ();
  237. if (frameLength == 0)
  238. {
  239. dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, false, false,
  240. "Socket is sending bad length"));
  241. socket.close ();
  242. return null;
  243. }
  244. decoderMinBytes = 1;
  245. return frameFlagsDecoder;
  246. }
  247. private function frameFlagsDecoder (bytes: ByteArray): Function
  248. {
  249. frameFlags = bytes.readUnsignedByte ();
  250. more = (frameFlags & 0x1) == 0x1;
  251. // Body length is 1 byte less than frame length (flags take 1 byte).
  252. decoderMinBytes = frameLength - 1;
  253. // If message contained only flags, we're done
  254. if (frameLength <= 1)
  255. {
  256. if (current == null)
  257. current = new Array;
  258. current.push (null);
  259. // If it's the last frame of message, push current message to queue.
  260. if (!more)
  261. {
  262. queue.push (current);
  263. current = null;
  264. return null;
  265. }
  266. else
  267. {
  268. // Reset decoder to read next frame.
  269. decoderMinBytes = 1;
  270. return frameLengthDecoder;
  271. }
  272. }
  273. return frameBodyDecoder;
  274. }
  275. private function frameBodyDecoder (bytes: ByteArray): Function
  276. {
  277. if (current == null)
  278. current = new Array;
  279. current.push (bytes);
  280. // If it's the last frame of message, push current message to queue.
  281. if (!more)
  282. {
  283. queue.push (current);
  284. current = null;
  285. return null;
  286. }
  287. else
  288. {
  289. // Reset decoder to read next frame.
  290. decoderMinBytes = 1;
  291. return frameLengthDecoder;
  292. }
  293. }
  294. private function connectHandler (event: Event): void
  295. {
  296. // Reset decoder.
  297. decoderMinBytes = 1;
  298. decoder = frameLengthDecoder;
  299. // Now we must send greeting
  300. writeFrame (identity);
  301. }
  302. private function socketDataHandler (event: ProgressEvent): void
  303. {
  304. // If frame hasn't arrived yet, just wait for more data.
  305. if (!readNextFrame ())
  306. return;
  307. // If we haven't got peer's identity yet, read it now.
  308. if (!connected)
  309. {
  310. // If peer says that identity has more than 1 frame, than he's bad.
  311. if (more)
  312. {
  313. dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, false, false,
  314. "Peer has malformed identity"));
  315. socket.close ();
  316. return;
  317. }
  318. else
  319. {
  320. // Accept peer's identity
  321. current = queue.shift () as Array;
  322. if (current.length > 0)
  323. peerIdentity = current.shift ();
  324. connected = true;
  325. dispatchEvent (new Event (OPEN));
  326. }
  327. }
  328. else
  329. {
  330. if (!more)
  331. dispatchEvent (new Event (MESSAGE));
  332. }
  333. }
  334. }
  335. }