/// <summary> /// The HandleTx method is invoked to request that an instance /// of the VfxTcpModule send the data in the specified message /// block out to the peer system it is connected to. /// </summary> /// <param name="mb"> /// The message block that contains the data that is to be sent /// to the peer system the module is connected to. /// </param> public void HandleTx(VfxMsgBlock mb) { if (_moduleState == ModuleStates.Module_State_Active) { // REC: Send all of the data in the buffer: while (mb.Length() > 0) { IoContext ctx = null; lock (_synchIoContextQueue) { if (_ioContextQueue.Count > 0) { ctx = _ioContextQueue.Dequeue(); } } if (ctx != null) { if (ctx._ipcBuffer.Remaining() >= mb.Length()) { // REC: Append the contents of the buffer // to the IO context's buffer and push it // onto the outgoing queue: ctx._ipcBuffer.UnsafeAppend(mb); mb.RdIndex = mb.WrIndex; InitiateSend(ctx, false); } else { // REC: Copy as much data as possible into // the context and attempt to send that: int txLength = ctx._ipcBuffer.Remaining(); ctx._ipcBuffer.UnsafeAppend(mb, txLength); // REC: Adjust the source buffer's index: mb.RdIndex += txLength; InitiateSend(ctx, false); } } else { // REC: Wait for a buffer to become available: _eventTxBuffer.WaitOne(); } } } }
/// <summary> /// The UnsafeAppend method is invoked to conduct an unsafe copy /// of the contents from an external messasge block into this one. /// </summary> /// <param name="src"></param> unsafe public void UnsafeAppend(VfxMsgBlock src) { fixed(byte *pDst = &_buffer[WrIndex]) { fixed(byte *pSrc = &src._buffer[src.RdIndex]) { for (int i = 0; i != src.Length(); i++) { pDst[i] = pSrc[i]; } } } WrIndex += src.Length(); }
/// <summary> /// The HandleRxMessage method is invoked by the owner of an /// instance of a session to inform it that data has arrived /// from the peer system. /// </summary> /// <param name="mb"> /// The message block that contains the data received from /// the peer system the session is communicating with. /// </param> public void HandleRxMessage(VfxEngine.Ipc.VfxMsgBlock mb) { string content = Encoding.ASCII.GetString(mb.Buffer, 0, mb.Length()); VfxFixParserResult fpr = _fixParser.Parse(content, null, null, null); while (fpr.Status == VfxFixParserStatus.MsgComplete) { // REC: Adjust the read index in the message block // to compensate for the number of bytes parsed from // the incoming data stream: mb.RdIndex += fpr.Consumed; // REC: Crunch the message block to remove the data // that has already been parsed: mb.Crunch(); // REC: Reset the timestamp that is used to determine // when the last message was received from the peer: this._lastRxTicks = DateTime.Now.Ticks; // REC: Determine if the message is a session layer // message and process it accordingly: FixField fldMsgType = fpr.Message.Header.GetField(35); if (fldMsgType != null) { string strMsgType = fldMsgType.Content; if (!string.IsNullOrEmpty(strMsgType)) { switch (strMsgType) { case "A": // Received a FIX logon message: HandleSession_Logon(fpr.Message); break; case "0": // Received a FIX heartbeat message: HandleSession_Heartbeat(fpr.Message); break; case "1": // Received a FIX test request: HandleSession_TestRequest(fpr.Message); break; case "2": // Received a FIX resend request: HandleSession_Resend(fpr.Message); break; case "5": // Received a FIX logout message: HandleSession_Logout(fpr.Message); break; default: // Received a message that should be // routed to the session's owner: HandleSession_Message(fpr.Message); break; } } else { // REC: If the session's identity hasn't been // established yet, just throw an exception and // let the session's owner shut it down: if (_currentState == SessionStates.Session_Pending) { throw new ArgumentException("Initial message missing required field - FIX MsgType."); } else { // REC: The session has been established, so the // session can send a reject message: } } } else { } // REC: Attempt to parse another message from // the buffer of data that has been received: content = Encoding.ASCII.GetString(mb.Buffer, 0, mb.Length()); fpr = _fixParser.Parse(content, null, null, null); } // REC: If the parser couldn't extract a complete message // from the supplied buffer, determine what to do next: if (fpr.Status != VfxFixParserStatus.MsgComplete) { } }
/// <summary> /// The Append method is invoked to append the content of an /// message block to the content of the current instance. /// </summary> /// <param name="src"> /// The message block that contains the data which is to be /// copied into the message block's buffer. /// </param> public void Append(VfxMsgBlock src) { System.Array.Copy(src.Buffer, src.RdIndex, _buffer, WrIndex, src.Length()); WrIndex += src.Length(); }
/// <summary> /// The HandleReceive_Entrypoint method is the entrypoint for /// the buffering thread that is started by the module if the /// module's owner has enabled incoming IO buffering. /// </summary> /// <param name="context"></param> private void HandleReceive_Entrypoint(object context) { // REC: The fragment buffer is used when there is residual // data remaining from a previously processed buffer. This // is allocated at 2x the receive block size, in order for // reducing the need to "expand" the fragment buffer when // data is left over from a receive operation: VfxMsgBlock rxFragment = new VfxMsgBlock(16384); while (true) { // REC: Lock the pending receive queue and check whether or not // there are any receive blocks waiting to be processed: IoContext rxPending = null; lock (this._synchRxPendingQueue) { if (this._rxPendingQueue.Count > 0) { rxPending = this._rxPendingQueue.Dequeue(); } } if (rxPending != null) { // REC: If there is data in the fragment buffer // then we need to append the data from the incoming // receive context to it: if (rxFragment.Length() > 0) { rxFragment.Append(rxPending._ipcBuffer); // REC: Dispatch from the fragment buffer instead // of from the receive context: EventHandler <VfxIpcEventArgs> tmp = EventDispatch; if (tmp != null) { tmp(this, new VfxIpcEventArgs(rxFragment)); rxFragment.Crunch(); } // REC: Reset the pointers in the receive context // since its data has been copied to the fragment // buffer for subsequent processing: rxPending._ipcBuffer.RdIndex = rxPending._ipcBuffer.WrIndex = 0; } else { // REC: There is no fragment remaining from the previous // receive operation, so we can just dispatch directly from // the received context: EventHandler <VfxIpcEventArgs> tmp = EventDispatch; if (tmp != null) { tmp(this, new VfxIpcEventArgs(rxPending._ipcBuffer)); rxPending._ipcBuffer.Crunch(); } // REC: Determine if there is a fragment in the buffer // so that we can chain it to subsequent blocks: if (rxPending._ipcBuffer.Length() > 0) { // REC: There is a fragment of a message remaining // in the current buffer, so it has to be copied into // the fragment buffer for further processing: rxFragment.Append(rxPending._ipcBuffer); // REC: Reset the points in the pending receive context // since it has been copied into the fragment buffer: rxPending._ipcBuffer.RdIndex = 0; rxPending._ipcBuffer.WrIndex = 0; } } // REC: Put the receive context back into the queue so // that it can be used by subsequent receive operations: lock (this._rxContextQueue) { this._rxContextQueue.Enqueue(rxPending); } } else { // REC: A message block wasn't available for us on this // iteration, so just wait until one is added to the queue: this._eventRxBuffer.WaitOne(); } } }