1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11 
12 
13 
14 
15 #ifndef _PacketIF_h
16 #define _PacketIF_h
17 
18 #include <stdio.h>
19 #include <X11/Intrinsic.h>
20 
21 #include "Base.h"
22 #include "PacketHandler.h"
23 #include "LinkHandler.h"
24 #include "List.h"
25 #include "QueuedPackets.h"
26 
27 #if defined(intelnt)  && defined(ERROR)
28 #undef ERROR
29 #endif
30 
31 
32 //
33 // Class name definition:
34 //
35 #define ClassPacketIF	"PacketIF"
36 
37 //
38 // XtCallbackProc (*CB), XtEventHandler (*EH) and XtActionProc (*AP)
39 // DialogCallback (*DCB), XtInputCallbackProc (*ICP), XtWorkProc (*WP)
40 // functions for this and derived classes
41 //
42 extern "C" void PacketIF_InputIdleTimerTCP(XtPointer, XtIntervalId*);
43 extern "C" Boolean PacketIF_InputIdleWP(XtPointer);
44 extern "C" Boolean PacketIF_QueuedPacketWP(XtPointer);
45 extern "C" void PacketIF_ProcessSocketInputICB(XtPointer, int*, XtInputId*);
46 
47 #if defined(DXD_IBM_OS2_SOCKETS)  || defined(DXD_HAS_WINSOCKETS)
48 int UxSend(int s, const char *ExternalBuffer, int TotalBytesToSend, int Flags);
49 int UxRecv(int s, char *ExternalBuffer, int BuffSize, int Flags);
50 #endif
51 
52 
53 typedef void (*PacketIFCallback)(void *clientData, char *echoString);
54 typedef boolean (*StallingHandler)(void *clientData);
55 
56 //
57 // PacketIF class definition:
58 //
59 class PacketIF : public Base
60 {
61 
62     //
63     // Allow the LinkHandlers to send packets.
64     //
65     friend void LinkHandler::sendPacket(int , int , const char *, int);
66     friend void QueuedPacket::send(PacketIF*);
67     friend void QueuedBytes::send(PacketIF*);
68     friend void QueuedImmediate::send(PacketIF*);
69 
70   private:
71     //
72     // Private member data:
73     //
74 
75     //
76     // I hate this... on some AIX systems, it seems that the work proc can
77     // get called even after the PacketIF deletion method is called.  When this
78     // happens, the work proc receives a deleted PacketIF, and all hell breaks
79     // loose.  Instead, I'm going to use double indirection... I'll allocate a
80     // pointer when the PacketIF is created, set it to point to the PacketIF
81     // itselfkeep a pointer to it in the PacketIF, and pass its address as the
82     // work proc client data.  When the PacketIF is deleted, the pointer is set
83     // to NULL, but not freed.  So if the pointer that the work proc receives as
84     // its client data points to NULL, we know that the PacketIF has been deleted
85     // and the work proc returns immediately.  Unfortunately, this leaks space
86     // for a pointer for each packetIF created.
87     //
88     PacketIF	     **wpClientData;
89 
90     int      	     error;
91     int      	     socket;
92     FILE    	     *stream;
93     XtInputId 	     inputHandlerId;
94     boolean	     deferPacketHandling;
95     XtWorkProcId     workProcId;
96     XtIntervalId     workProcTimerId;
97     int      	     line_length;
98     int      	     alloc_line_length;
99 
100     friend void      PacketIF_InputIdleTimerTCP(XtPointer, XtIntervalId*);
101     friend Boolean   PacketIF_InputIdleWP(XtPointer clientData);
102     friend Boolean   PacketIF_QueuedPacketWP(XtPointer clientData);
103     friend void	     PacketIF_ProcessSocketInputICB(XtPointer clientData,
104 						       int *socket,
105 						       XtInputId *id);
106     PacketIFCallback echoCallback;
107     void             *echoClientData;
108 
109     PacketIFCallback errorCallback;
110     void             *errorClientData;
111 
112     boolean          endReceiving;
113     void             *endReceiveData;	// Data passed back by
114 
115     StallingHandler   stallingWorker;
116     void 	     *stallingWorkerData;
117 
118     /*
119      * Open a socket port and wait for a client to connect.
120      * This opens 2 sockets (except on the server), one internet domain, and
121      * one unix domain.  It then selects on both sockets to see to which one the
122      * app connects, and returns the new connection, closing the one not
123      * selected.
124      */
125     void connectAsServer(int pport);
126 
127     void connectAsClient(const char *host, int port, boolean local);
128 
129     //
130     // Control whether or not the callbacks to handle messages on the
131     // wire will be called.
132     //
133     void installInputHandler();
134     void removeInputHandler();
135 
136     //
137     // These methods are used to make the handling of packets a lower
138     // priority than the events coming from the display.  Basically,
139     // we don't enable the handling of a message until the WorkProc
140     // is called (indicating that there are no other events to handle).
141     //
142     void installWorkProc();
143     void removeWorkProc();
144     void installWorkProcTimer();
145     void removeWorkProcTimer();
146 
147 
148   protected:
149     //
150     // Protected member data:
151     //
152 
153     List     	     handlers;		// List of PacketHandler's.
154 
155     virtual void     parsePacket();
156     char    	     *line;
157 
158 
159     //
160     // Handle stream read/write errors.  We handle SIGPIPE/EPIPE specially.
161     // SIGPIPE is ignored and then if we get an EPIPE on a write, then we
162     // know the server or other connect has gone away.
163     // The errnum is passed in for portability, but is ignored on UNIX
164     // systems.
165     //
166     void handleStreamError(int errnum, const char *msg);
167 
168     //
169     // Receive a packet.
170     // If readSocket is FALSE, then we just process packets that are still
171     // in the line buffer.
172     //
173     void packetReceive(boolean readSocket = TRUE);
174 
175     //
176     // Routines to handle PacketIF messages.
177     //
178     static void ProcessMessage(void *clientData, int id, void *line);
179     static void ProcessInformation(void *clientData, int id, void *line);
180     static void ProcessError(void *clientData, int id, void *line);
181     static void ProcessErrorWARNING(void *clientData, int id, void *line);
182     static void ProcessErrorERROR(void *clientData, int id, void *p);
183     static void ProcessCompletion(void *clientData, int id, void *line);
184     static void ProcessInterrupt(void *clientData, int id, void *line);
185     static void ProcessBeginExecNode(void *clientData, int id, void *line);
186     static void ProcessEndExecNode(void *clientData, int id, void *line);
187     static void ProcessLinkCommand(void *clientData, int id, void *p);
188     static void HandleError(void *clientData, char *message);
189 
190     LinkHandler      *linkHandler;
191     virtual void      installLinkHandler();
192 
193     //
194     // Queue outgoing messages in order to avoid deadlock with dxexec
195     //
196     void _sendBytes(const char *string);
197     void _sendImmediate(const char *string);
198     void _sendPacket(int type, int packetId, const char *data = NULL, int length = 0);
199     Boolean sendQueuedPackets();
200     boolean isSocketInputReady();
201     List output_queue;
202     int output_queue_wpid;
203     void sendPacket(int type, int packetId, const char *data = NULL, int length = 0);
204 
205   public:
206 
207     static const char* PacketTypes[];
208 
209     enum {
210 	INTERRUPT        = 1,
211 	SYSTEM           = 2,
212 	ACK              = 3,
213 	MACRODEF         = 4,
214 	FOREGROUND       = 5,
215 	BACKGROUND       = 6,
216 	PKTERROR         = 7,
217 	MESSAGE          = 8,
218 	INFORMATION      = 9,
219 	LINQUIRY         = 10,
220 	LRESPONSE        = 11,
221 	LDATA            = 12,
222 	SINQUIRY         = 13,
223 	SRESPONSE        = 14,
224 	SDATA            = 15,
225 	VINQUIRY         = 16,
226 	VRESPONSE        = 17,
227 	VDATA            = 18,
228 	COMPLETE         = 19,
229 	IMPORT           = 20,
230 	IMPORTINFO       = 21,
231 	LINK	         = 22
232     };
233 
234     //
235     // Constructor:
236     //
237     PacketIF(const char *server, int port, boolean local, boolean asClient);
238 
239     //
240     // Destructor:
241     //
242     ~PacketIF();
243 
244     //
245     // Initializer
246     //
247     virtual void initializePacketIO();
248 
inError()249     int inError() {return this->error;}
250 
251     void setHandler(int type,
252 		    PacketHandlerCallback callback,
253 		    void *clientData,
254 		    const char *matchString = NULL);
255 
256     //
257     // Error and echo handling callbacks.  Echos are not performed if no
258     // callback has been set up.  Errors are dumped to stderr if nothing
259     // has been set up.
260     //
261     void setErrorCallback(PacketIFCallback callback, void *clientData);
262     PacketIFCallback getErrorCallback(void **clientData = NULL);
263     void setEchoCallback(PacketIFCallback callback, void *clientData);
264     PacketIFCallback getEchoCallback(void **clientData = NULL);
265 
266     void sendBytes(const char *string);
267     void sendImmediate(const char *string);
268 
269     //
270     // Return TRUE if there was NOT a packet error.
271     // If returning TRUE and data!=NULL, then *data is set to the value
272     // passed to the endReceiveContinuous() call.
273     //
274     boolean receiveContinuous(void **data = NULL);
275 
276     //
277     // Terminates receiveContinuous() and causes it to set its *data to
278     // the data value passed in.
279     //
280     void endReceiveContinuous(void *data  = NULL);
281 
282     //
283     // This is the file descriptor.  It may ONLY be used to write a
284     // network to the executive between sendMacroStart and sendMacroEnd.
285     // Anything written to this FILE must be also sent to the routine
286     // accessed via "getEchoCallback".
getFILE()287     FILE *getFILE() { return this->stream; }
288 
289 
290     void         executeLinkCommand(const char *c, int id);
291 
292     //
293     // Defer handing of messages until the function h is called (periodically)
294     // and returns TRUE.  At that point handling is reenabled.
295     // If stalling was not already enabled and there are no other problems,
296     // then we return TRUE, otherwise FALSE.
297     // Use isPacketHandlingStalled() to determine if handling is currently
298     // stalled.
299     //
300     boolean stallPacketHandling(StallingHandler h, void *data);
301     boolean isPacketHandlingStalled();
302 
303     //
304     // Returns a pointer to the class name.
305     //
getClassName()306     const char* getClassName()
307     {
308 	return ClassPacketIF;
309     }
310 };
311 #endif // _PacketIF_h
312