//////////////////////////////////////////////////////////////////////////////// // // enginewrapper.hpp // // This header file contains driver's interface to class DrivenEngine. // This is meant to be used across a DLL boundary. Since the DLL may have // been compiled by a different compiler than the driver, we use only simple // POD types and we only use C calling conventions. // // When calling a wrapper function, you must always pass in the wrapper as // the first parameter. // //////////////////////////////////////////////////////////////////////////////// #ifndef ENGINEWRAPPER_H #define ENGINEWRAPPER_H #define DRV_MAX_CHAN 256 #define DRV_MAX_LISTEN_PORTS 256 #define DRV_ERRMSG_SIZE 8192 #define DRV_SHORTSTRING_SIZE 65536 class DrivenEngine; class PlayLogfile; class ReplayLogfile; struct EngineWrapper { char error[DRV_ERRMSG_SIZE]; char databuffer[DRV_SHORTSTRING_SIZE]; DrivenEngine *engine; PlayLogfile *wlog; ReplayLogfile *rlog; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // CONSTRUCTION // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Of course, there's no constructor, since this is a C struct. // To initialize it, you use 'dlsym' or 'GetProcAddress' to get the // address of the function 'init_engine_wrapper'. Then, you call // the function init_engine_wrapper(&wrapper). ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // GETTERS // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Get a list of all the listening ports. The driver is expected // to fetch this set shortly after the event_init callback is invoked. // void (*get_listen_ports)(EngineWrapper *w, uint32_t *nports, const uint32_t **ports); // Get a list of all recently-opened channels that were created using // new_outgoing_channel. The driver should initiate outgoing // connections for these channels. // void (*get_new_outgoing)(EngineWrapper *w, uint32_t *nchanids, const uint32_t **chanids); // Get a string_view of the target of a channel. A target is a string like // "cert:whatever.com:80" or "nocert:whatever.com:80". // The first word indicate whether or not a valid SSL certificate // is required. The second word is the hostname. The third word is // the port number. The char string returned here is valid until // the channel is closed. // const char *(*get_target)(EngineWrapper *w, uint32_t chid); // Return true if the user has released all references to this channel. // In this case, the driver should initiate shutdown of the channel, // and the driver should eventually call notify_close. // bool (*get_channel_released)(EngineWrapper *w, uint32_t chid); // Get a pointer to the bytes in the outgoing buffer. The char pointer // returned here is naturally only valid until the buffer is changed. // This function is used for all channels, including sockets and stdio. // void (*get_outgoing)(EngineWrapper *w, uint32_t chid, uint32_t *len, const char **data); // Return true if the outgoing buffer is empty. // bool (*get_outgoing_empty)(EngineWrapper *w, uint32_t chid); // Get the clock. // // Get the current time. This is equal to the last value passed // in by invoke_event_update. // double (*get_clock)(EngineWrapper *w); // Check the 'rescan_lua_source' flag. If this flag is set, it means // that the engine wants the driver to rescan the lua source code. // When the driver sees this flag, it should rescan the source and call // set_lua_source. // bool (*get_rescan_lua_source)(EngineWrapper *w); // If true, the engine is done. Stop the driver. // bool (*get_stop_driver)(EngineWrapper *w); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // MUTATORS USED ONLY IN PLAY MODE // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Create the driven engine. argc and argv allow you to specify what // kind of engine you want. You must pass in the initial state of the lua // source, if you have any. You may optionally also specify a replay log. // If you don't want to create a replay log, pass a null pointer. // // Check to see if the error buffer contains a message after calling // this function. // void (*play_initialize)(EngineWrapper *w, uint32_t argc, char **argv, uint32_t srcpklen, const char *srcpk, const char *logfn); // Clear the list of recently-opened channels. You are meant to fetch // new outgoing channels using get_new_outgoing, then you call // clear_new_outgoing after you've opened those channels. // void (*play_clear_new_outgoing)(EngineWrapper *w); // Notifies the channel that some bytes were transmitted. This causes those // bytes to be removed from the outgoing buffer. This function is used for // all channels, including sockets and stdio. // void (*play_sent_outgoing)(EngineWrapper *w, uint32_t chid, uint32_t nbytes); // Notifies the channel that some bytes were received. This causes those // bytes to be appended to the incoming buffer. This function is used for // all channels, including sockets and stdio. // void (*play_recv_incoming)(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data); // Notify the channel that the connection was closed. This includes all // sorts of closes, including friendly termination, all the way to network // failure. Closing the channel doesn't delete it. The engine is // responsible for noticing that the channel closed and the engine must // delete it. Closing a channel prevents it from showing up in // 'list_channels'. // void (*play_notify_close)(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data); // Notify the DrivenEngine that somebody connected to an incoming port. // This will cause the DrivenEngine to allocate a new channel and put the // new channel into the incoming channels queue. Returns the new channel // ID. The new incoming channel appears in the 'list_channels' list, // even before the engine pops the channel from the incoming channels queue. // uint32_t (*play_notify_accept)(EngineWrapper *w, uint32_t port); // Invoke the update event. // // The clock value must absolutely be monotonically increasing, // and it should roughly be equal to the number of seconds since // the program started. // void (*play_invoke_event_update)(EngineWrapper *w, double clock); // Store the lua source code. // void (*play_set_lua_source)(EngineWrapper *w, uint32_t srcpklen, const char *srcpk); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // MUTATORS USED ONLY IN REPLAY MODE // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Begin a replay. // // Opens the logfile and prepares to replay the log. // If an error occurs, the error buffer contains a message, // and the done flag is set to true. // void (*replay_initialize)(EngineWrapper *w, const char *logfn); // Execute a single step from the replay log. // // Calling this when 'done' is true is a no-op. // void (*replay_step)(EngineWrapper *w); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // FUNCTIONS THAT CAN BE USED AT ANY TIME // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Restore the wrapper to its initial blank state. // // Note that the wrapper must have already been initialized using // init_engine_wrapper. Otherwise, the 'release' function pointer would not // be initialized. If writing a logfile, this stores a 'clean exit' marker // in the logfile, indicating that the engine exited cleanly, as opposed to // crashing. // // If the wrapper is already in its clear state, this is a no-op. // void (*release)(EngineWrapper *w); }; #endif // ENGINEWRAPPER_HPP