OnixS C++ FIX Engine exposes the OnixS::FIX::ISessionListener class, whose virtual members are called by an instance of the OnixS::FIX::Session class, as response to a particular event occurred during the session life-time.
To be notified about a particular session event, override the appropriate member of the OnixS::FIX::ISessionListener class, and supply a derived-class instance to the OnixS::FIX::Session's constructor.
The following table describes the meaning of all events, exposed by the OnixS::FIX::Session class in terms of OnixS::FIX::ISessionListener class members.
| Method (Event handler) | Description |
|---|---|
| onInboundApplicationMsg | Application-level message is received from the counterparty. |
| onInboundSessionMsg | Session-level message is received from the counterparty. |
| onOutboundApplicationMsg | Application-level message will be sent to the counterparty. This callback could be used to change fields set by the FIX Engine. |
| onOutboundSessionMsg | Session-level message will be sent to the counterparty. This callback could be used to change fields set by the FIX Engine. |
| onReceivedBytes | Bytes are received from the wire. |
| onMessageSending | Just before the FIX message is sent to the wire. |
| onResendRequest | Sent application-level message is about to be resent to the counterparty. |
| onResendingStarted | ResendRequest message is received and the session is about to start resending messages. |
| onResendingFinished | Resending process is completed. |
| onWarning | Warning condition is detected. |
| onError | Error condition is detected. |
| onStateChange | Session state is changed. |
See FIX Engine Threading Models for the threads that can invoke callbacks.
| Callback | Operations to avoid and deadlock risks | Data to copy for later use |
|---|---|---|
| onInboundApplicationMsg, onInboundSessionMsg | Avoid slow processing and blocking waits; use Asynchronous Processing of Incoming Messages. | Required message fields or an independent message copy. |
| onReceivedBytes | Do not block network processing. | Received bytes and timestamp values. |
| onOutboundApplicationMsg, onOutboundSessionMsg | Same-session sends have batch and resend restrictions; see Sending Messages from Outbound Callbacks. Cross-session calls can deadlock. | Required message fields or an independent message copy. |
| onMessageSending | Do not send on the same session. Cross-session calls can deadlock. | Sequence number and any available bytes; FlatMessage supplies no buffer. |
| onResendRequest, onResendingStarted, onResendingFinished | Keep processing short; do not send on the same session from onResendRequest. See Resending Messages for the resend policy. | Required message fields from onResendRequest. |
| onStateChange | Avoid calls that change another session's state and can create a lock cycle. | State values. |
| onError, onWarning | Do not send on the same session when reporting a condition from its sending operation. Avoid recursive error handling. | Reason and description values. |
The Engine supplies temporary message wrappers to message callbacks. Do not retain their addresses or references, field references, or pointers into their contents after the callback returns. Likewise, copy raw bytes, timestamp values, and error or warning descriptions before using them later. Do not assume that holding a pointer keeps the data alive.
Copy the fields needed by deferred work into application-owned values, or make an independent message copy. A copied pointer to message user data does not copy the object it points to; its lifetime remains the application's responsibility. FlatMessage field references can also become invalid when the message is changed or sent; see Accessing FIX Fields. The Async Processing Sample demonstrates copying incoming messages for a worker thread.
The Engine does not own session listeners. Register all listeners before connecting, and keep them alive until the session has finished calling them. Do not register or unregister listeners from a callback of that same session, or concurrently with callback dispatch: dispatch iterates the listener collection, and changing that collection can invalidate the iteration.
Both OnixS::FIX::Session::unregisterListener and OnixS::FIX::Session::unregisterAllListeners throw unless the session is OnixS::FIX::SessionState::Disconnected. Being disconnected does not itself wait for callbacks already running, so arrange for dispatch and other calls that can invoke callbacks to finish before removing or destroying listeners.
The outbound callbacks are called while the session is preparing a message for sending, so a message sent from such a callback can reach the wire before the message being prepared, while carrying a higher MsgSeqNum value. The counterparty then receives a message whose sequence number is less than expected while the PossDupFlag is not set, which the FIX protocol treats as a serious error requiring the FIX session to be terminated.
Whether this can happen depends on the callback:
Of the outbound message callbacks, OnixS::FIX::FlatMessage sending supports only onMessageSending, with a null buffer and zero length; onOutboundApplicationMsg and onOutboundSessionMsg are not called. This applies to single-message and batch sends, send-mode overloads, OnixS::FIX::Session::sendAsIs, and a custom FlatMessage Logout sent by OnixS::FIX::Session::logout or OnixS::FIX::Session::logoutAsync. See FAQ Q18 for the buffer explanation. Therefore, sending a message from within any callback triggered by such a send operation is not supported.
The onError and onWarning callbacks are also called while a message is prepared for sending when they report a condition detected by the sending itself, for example the rejection described above. Sending a message on the same session from them is not supported in such a case and throws an exception for the same reason.
For a supported way to defer sending, see Deferred Processing and Shutdown.
The OnixS::FIX::Session::logout and OnixS::FIX::Session::logoutAsync methods are affected because they produce the Logout message, and the OnixS::FIX::Session::resetSeqNumViaLogonExchange method is affected because it produces the Logon message. The OnixS::FIX::Session::breakConnection method is not affected, because it terminates the FIX connection without the Logout message.
The restriction is per session, so sending a message on a different session from these callbacks is outside this restriction. It can still deadlock through lock ordering; see Callback Safety.
Copy the required data in the callback and return. For callbacks triggered by an application sending call, perform deferred operations after that call returns.
In ExternalThread mode, callbacks for dispatched network events run synchronously during OnixS::FIX::ISessionReactor::dispatchEvents. Keep callbacks short, do not block, and do not call dispatchEvents recursively. Record any requests and copy the data needed to act on them after the callback returns. Perform deferred session operations on the reactor-owning thread between calls to dispatchEvents:
Here, stop and processApplicationWork() are application-defined. Both calls run on the same thread. Keep application work bounded so that dispatchEvents() is called frequently enough to meet latency requirements and process network events and timers. Calls such as OnixS::FIX::Session::send can invoke callbacks directly, before returning to application work.
Use asynchronous logon and logout, and continue dispatching while those operations are pending; see Asynchronous Logon and Logout. For more capacity, assign separate stacks and session groups to separate threads; see Split the Sessions Processing by Different Stacks in Separate Threads.
With DedicatedThreads or ThreadPool, a synchronized queue can hand work to another application thread; do not wait for that thread from the callback or hold an application lock while calling the session. If an ExternalThread application offloads processing to a worker, the worker must return any resulting session operations to the reactor-owning thread; see Asynchronous Processing of Incoming Messages.
Request application shutdown outside callbacks. Stop accepting new application work and finish or discard pending work before destroying the objects it uses. Keep listeners alive while sessions shut down. Follow Shutting down the whole Application and, for externally managed reactors, Shutdown.