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