1 #ifndef _PROTO_CHANNEL 2 #define _PROTO_CHANNEL 3 /** 4 * @class ProtoChannel 5 * 6 * @brief This class serves as a base class for Protokit classes 7 * which require asynchronous I/O. 8 * 9 * This uses a sort of "signal/slot" design pattern 10 * for managing a single listener. 11 * 12 * On Unix, a file descriptor serves as the "NotifyHandle" 13 * On Win32, events and overlapping I/O are used 14 * 15 * NOTE: This is a work-in-progress !!! 16 * The intent of this class will be to serve as a _base_ 17 * class for any class requiring asynchronous I/O 18 * notification and event dispatch (eventually including ProtoSockets?) 19 * This will help extend & simplify the utility of the 20 * ProtoDispatcher class 21 */ 22 23 #include "protoDefs.h" 24 25 class ProtoChannel 26 { 27 public: 28 virtual ~ProtoChannel(); 29 30 #ifdef WIN32 31 typedef HANDLE Handle; // WIN32 uses "HANDLE" type for descriptors 32 #else 33 typedef int Handle; // UNIX uses "int" type for descriptors 34 #endif // if/else WIN32 35 static const Handle INVALID_HANDLE; 36 37 // Derived classes should _end_ their own "Open()" method 38 // with a call to this Open()39 bool Open() 40 { 41 StartInputNotification(); // enable input notifications by default 42 return UpdateNotification(); 43 } 44 // Derived classes should _begin_ their own "Close()" method 45 // with a call to this Close()46 void Close() 47 { 48 if (IsOpen()) 49 { 50 StopInputNotification(); 51 StopOutputNotification(); 52 } 53 } 54 // (TBD) Should this be made virtual??? IsOpen()55 bool IsOpen() const 56 { 57 #ifdef WIN32 58 return ((INVALID_HANDLE != input_handle) || 59 (INVALID_HANDLE != output_handle)); 60 #else 61 return (INVALID_HANDLE != descriptor); 62 #endif // if/else WIN32/UNIX 63 64 } 65 66 // Asynchronous I/O notification stuff 67 enum Notification 68 { 69 NOTIFY_NONE = 0x00, 70 NOTIFY_INPUT = 0x01, 71 NOTIFY_OUTPUT = 0x02 72 }; 73 /** 74 * @class Notifier 75 * 76 */ 77 class Notifier 78 { 79 public: ~Notifier()80 virtual ~Notifier() {} 81 // This should usually be overridden UpdateChannelNotification(ProtoChannel & theChannel,int notifyFlags)82 virtual bool UpdateChannelNotification(ProtoChannel& theChannel, 83 int notifyFlags) 84 { 85 return true; 86 } 87 }; GetNotifier()88 Notifier* GetNotifier() const {return notifier;} 89 bool SetNotifier(ProtoChannel::Notifier* theNotifier); 90 bool SetBlocking(bool status); 91 StartOutputNotification()92 bool StartOutputNotification() 93 { 94 notify_flags |= (int)NOTIFY_OUTPUT; 95 bool result = UpdateNotification(); 96 #ifdef WIN32 97 output_ready = result; 98 #endif // WIN32 99 return result; 100 } StopOutputNotification()101 void StopOutputNotification() 102 { 103 notify_flags &= ~((int)NOTIFY_OUTPUT); 104 UpdateNotification(); 105 } OutputNotification()106 bool OutputNotification() 107 {return (0 != (notify_flags & ((int)NOTIFY_OUTPUT)));} 108 StartInputNotification()109 bool StartInputNotification() 110 { 111 notify_flags |= (int)NOTIFY_INPUT; 112 bool result = UpdateNotification(); 113 return result; 114 } StopInputNotification()115 void StopInputNotification() 116 { 117 notify_flags &= ~((int)NOTIFY_INPUT); 118 UpdateNotification(); 119 } InputNotification()120 bool InputNotification() 121 {return (0 != (notify_flags & ((int)NOTIFY_INPUT)));} 122 123 bool UpdateNotification(); 124 OnNotify(ProtoChannel::Notification theNotification)125 void OnNotify(ProtoChannel::Notification theNotification) 126 { 127 if (listener) listener->on_event(*this, theNotification); 128 } 129 130 131 #ifdef WIN32 GetInputHandle()132 Handle GetInputHandle() {return input_handle;} GetOutputHandle()133 Handle GetOutputHandle() {return output_handle;} IsOutputReady()134 bool IsOutputReady() {return output_ready;} IsInputReady()135 bool IsInputReady() {return input_ready;} IsReady()136 bool IsReady() {return (input_ready || output_ready);} 137 #else GetInputHandle()138 Handle GetInputHandle() {return descriptor;} GetOutputHandle()139 Handle GetOutputHandle() {return descriptor;} GetHandle()140 Handle GetHandle() {return descriptor;} 141 #endif // if/else WIN32/UNIX 142 143 // NOTE: For VC++ 6.x Debug builds "/ZI" or "/Z7" compile options must NOT be specified 144 // (or else VC++ 6.x experiences an "internal compiler error") 145 template <class listenerType> SetListener(listenerType * theListener,void (listenerType::* eventHandler)(ProtoChannel &,Notification))146 bool SetListener(listenerType* theListener, void(listenerType::*eventHandler)(ProtoChannel&, Notification)) 147 { 148 bool doUpdate = ((NULL == listener) && (NULL != theListener)) || 149 ((NULL == theListener) && (NULL != listener)); 150 if (listener) delete listener; 151 listener = theListener ? new LISTENER_TYPE<listenerType>(theListener, eventHandler) : NULL; 152 bool result = theListener ? (NULL != theListener) : true; 153 return result ? (doUpdate ? UpdateNotification() : true) : false; 154 } HasListener()155 bool HasListener() {return (NULL != listener);} 156 157 protected: 158 ProtoChannel(); 159 160 private: 161 /** 162 * @class Listener 163 * 164 */ 165 166 class Listener 167 { 168 public: ~Listener()169 virtual ~Listener() {} 170 virtual void on_event(ProtoChannel& theChannel, Notification theNotification) = 0; 171 virtual Listener* duplicate() = 0; 172 }; 173 template <class listenerType> 174 class LISTENER_TYPE : public Listener 175 { 176 public: LISTENER_TYPE(listenerType * theListener,void (listenerType::* eventHandler)(ProtoChannel &,Notification))177 LISTENER_TYPE(listenerType* theListener, 178 void(listenerType::*eventHandler)(ProtoChannel&, Notification)) 179 : listener(theListener), event_handler(eventHandler) {} on_event(ProtoChannel & theChannel,Notification theNotification)180 void on_event(ProtoChannel& theChannel, Notification theNotification) 181 {(listener->*event_handler)(theChannel, theNotification);} duplicate()182 Listener* duplicate() 183 {return (static_cast<Listener*>(new LISTENER_TYPE<listenerType>(listener, event_handler)));} 184 private: 185 listenerType* listener; 186 void(listenerType::*event_handler)(ProtoChannel&, Notification); 187 }; 188 189 Listener* listener; 190 Notifier* notifier; 191 int notify_flags; 192 193 bool blocking_status; 194 195 protected: 196 #ifdef WIN32 197 // ljt rework this!! SetInputHandle(Handle theInputHandle)198 void SetInputHandle(Handle theInputHandle) 199 {input_handle = theInputHandle;} 200 HANDLE input_handle; 201 bool input_ready; 202 HANDLE output_handle; 203 bool output_ready; 204 #else 205 int descriptor; 206 #endif // WIN32 207 208 }; // end class ProtoChannel 209 210 #endif // PROTO_CHANNEL 211