#ifndef _MGEN #define _MGEN #include "protokit.h" #include "mgenFlow.h" #include "mgenMsg.h" class DrecGroupList { public: DrecGroupList(); ~DrecGroupList(); // (TBD) make socketList argument of constructor or Init() method ??? void Destroy(MgenSocketList& socketList); bool JoinGroup(MgenSocketList& socketList, const ProtoAddress& groupAddress, const char* interfaceName = NULL, unsigned short thePort = 0, bool deferred = false); bool LeaveGroup(MgenSocketList& socketList, const ProtoAddress& groupAddress, const char* interfaceName = NULL, unsigned short thePort = 0); bool JoinDeferredGroups(MgenSocketList& socketList); private: class Item { friend class DrecGroupList; public: Item(const ProtoAddress& groupAddr, const char* interfaceName, unsigned short thePort); ~Item(); void SetInterface(const char* interfaceName) { if (interfaceName) strncpy(interface_name, interfaceName, 16); else interface_name[0] = '\0'; } const char* GetInterface() {return (('\0' != interface_name[0]) ? interface_name : NULL);} bool IsActive() {return (NULL != socket_item);} bool Activate(MgenSocketList& socketList) { const char* iface = GetInterface(); socket_item = socketList.JoinGroup(group_addr, iface, port); return IsActive(); } unsigned short GetPort() {return port;} private: MgenSocketList::Item* socket_item; ProtoAddress group_addr; char interface_name[16]; unsigned short port; Item* prev; Item* next; }; // end class DrecGroupList::Item Item* FindItemByGroup(const ProtoAddress& groupAddr, const char* interfaceName = NULL, unsigned short thePort = 0); void Append(Item* item); void Remove(Item* item); Item* head; Item* tail; }; // end class DrecGroupList class MgenController { public: virtual ~MgenController(); virtual void OnMsgReceive(const MgenMsg& msg, const ProtoAddress& src, const struct timeval& currentTime) = 0; protected: MgenController(); }; // end class MgenController class Mgen { public: enum {SCRIPT_LINE_MAX = 512}; // maximum script line length enum LogEvent { INVALID_EVENT = 0, RECV_EVENT, RERR_EVENT, SEND_EVENT, LISTEN_EVENT, IGNORE_EVENT, JOIN_EVENT, LEAVE_EVENT, START_EVENT, STOP_EVENT }; Mgen(ProtoTimerMgr& timerMgr, ProtoSocket::Notifier& socketNotifier); ~Mgen(); // MGEN "global command" set enum Command { INVALID_COMMAND, EVENT, START, // specify absolute start time INPUT, // input and parse an MGEN script OUTPUT, // open output (log) file LOG, // open log file for appending NOLOG, // no output TXLOG, // turn transmit logging on DLOG, // set debug log file SAVE, // save pending flow state/offset info on exit. DEBUG, // specify debug level OFFSET, // time offset into script TXBUFFER, // Tx socket buffer size RXBUFFER, // Rx socket buffer size LABEL, // IPv6 flow label TOS, // IPV4 Type-Of-Service TTL, // IPV4 Time-To-Live INTERFACE, //Multicast Interface BINARY, // turn binary logfile mode on FLUSH, // flush log after _each_ event CHECKSUM, // turn on _both_ tx and rx checksum options TXCHECKSUM,// include checksums in transmitted MGEN messages RXCHECKSUM // force checksum validation at receiver _always_ }; static Command GetCommandFromString(const char* string); enum CmdType {CMD_INVALID, CMD_ARG, CMD_NOARG}; static CmdType GetCmdType(const char* cmd); bool OnCommand(Mgen::Command cmd, const char* arg, bool override = false); void SetController(MgenController* theController) {controller = theController;} MgenSink* GetSink() {return sink;} void SetSink(MgenSink* theSink) { sink = theSink; flow_list.SetSink(theSink); } void HandleMgenMessage(char* buffer, unsigned int len, const ProtoAddress& srcAddr); bool OpenLog(const char* path, bool append, bool binary); void CloseLog(); void SetLogFile(FILE* filePtr); typedef int (*LogFunction)(FILE*, const char*, ...); #ifndef _WIN32_WCE static LogFunction Log; #else static LogFunction Log; // Alternative logging function for WinCE debug window when logging to stdout/stderr static int Mgen::LogToDebug(FILE* filePtr, const char* format, ...); #endif // if/else _WIN32_WCE bool ParseScript(const char* path); bool ParseEvent(const char* lineBuffer, unsigned int lineCount); double GetCurrentOffset() const; void InsertDrecEvent(DrecEvent* event); void SetDefaultSocketType(ProtoAddress::Type addrType) {addr_type = addrType;} ProtoAddress::Type GetDefaultSocketType() {return addr_type;} void SetPositionCallback(MgenPositionFunc* callback, const void* clientData) { get_position = callback; get_position_data = clientData; } void SetHostAddress(const ProtoAddress hostAddr) { host_addr = hostAddr; flow_list.SetHostAddress(hostAddr); } void ClearHostAddress() { host_addr.Invalidate(); flow_list.ClearHostAddress(); } #ifdef HAVE_GPS void SetPayloadHandle(GPSHandle payloadHandle) { payload_handle = payloadHandle; } #endif // HAVE_GPS bool Start(); void Stop(); bool DelayedStart() {return start_timer.IsActive();} void GetStartTime(char* buffer) { sprintf(buffer, "%02d:%02d:%02.0f%s", start_hour, start_min, start_sec, (start_gmt ? "GMT" : "")); } bool ConvertBinaryLog(const char* path); // A little utility class for reading script files line by line class FastReader { public: enum Result {OK, ERROR_, DONE}; // trailing '_' for WIN32 FastReader(); FastReader::Result Read(FILE* filePtr, char* buffer, unsigned int* len); FastReader::Result Readline(FILE* filePtr, char* buffer, unsigned int* len); FastReader::Result ReadlineContinue(FILE* filePtr, char* buffer, unsigned int* len, unsigned int* lineCount = NULL); private: enum {BUFSIZE = 1024}; char savebuf[BUFSIZE]; char* saveptr; unsigned int savecount; }; // end class FastReader private: // MGEN script command types ("global" commands) // for mapping protocol types from script line fields static const StringMapper COMMAND_LIST[]; bool OnStartTimeout(ProtoTimer& theTimer); bool OnDrecEventTimeout(ProtoTimer& theTimer); void ProcessDrecEvent(const DrecEvent& event); void LogDrecEvent(LogEvent eventType, const DrecEvent& event, unsigned short portNumber); void OnSocketEvent(ProtoSocket& theSocket, ProtoSocket::Event theEvent); // Common state MgenController* controller; // optional MgenController ProtoTimerMgr& timer_mgr; MgenSocketList socket_list; MgenSink* sink; FILE* log_file; bool log_binary; bool log_flush; bool log_file_lock; bool log_tx; bool log_open; bool log_empty; char* save_path; bool save_path_lock; bool started; ProtoTimer start_timer; unsigned int start_hour; // absolute start time unsigned int start_min; double start_sec; bool start_gmt; bool start_time_lock; double offset; bool offset_lock; bool offset_pending; // (TBD) move these two to MgenSocketList ??? UINT32 default_flow_label; bool default_label_lock; ProtoAddress host_addr; bool checksum_enable; MgenFlowList flow_list; // Drec state ProtoTimer drec_event_timer; MgenEventList drec_event_list; DrecEvent* next_drec_event; // for iterating drec_event_list DrecGroupList drec_group_list; ProtoAddress::Type addr_type; bool checksum_force; // force checksum validation at rcvr MgenPositionFunc* get_position; const void* get_position_data; #ifdef HAVE_GPS GPSHandle payload_handle; #endif // HAVE_GPS }; // end class Mgen #endif // _MGEN