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 #include <stdio.h>
14 #include <ctype.h>
15 
16 #if defined(HAVE_SYS_TYPES_H)
17 #include <sys/types.h>
18 #endif
19 
20 #if defined(windows) && defined(HAVE_WINSOCK_H)
21 #include <winsock.h>
22 #elif defined(HAVE_CYGWIN_SOCKET_H)
23 #include <cygwin/socket.h>
24 #elif defined(HAVE_SYS_SOCKET_H)
25 #include <sys/socket.h>
26 #endif
27 
28 #if defined(HAVE_SYS_TIMEB_H)
29 #include <sys/timeb.h>
30 #endif
31 
32 #if defined(HAVE_SYS_TIME_H)
33 #include <sys/time.h>
34 #endif
35 
36 #if defined(HAVE_NETDB_H)
37 #include <netdb.h>
38 #endif
39 
40 #include <errno.h>
41 
42 #if defined(HAVE_STRING_H)
43 #include <string.h>
44 #endif
45 
46 #if defined(HAVE_MALLOC_H)
47 #include <malloc.h>
48 #endif
49 
50 #if defined(HAVE_SYS_SELECT_H)
51 #include <sys/select.h>
52 #endif
53 
54 #if defined(HAVE_UNISTD_H)
55 #include <unistd.h>
56 #endif
57 
58 #if   defined(OS2)  || defined(DXD_HAS_WINSOCKETS)
59 #if defined(HAVE_IO_H)
60 #include <io.h>
61 #endif
62 #define write(a,b,c) _dxl_os2_send(a,b,c,0)
63 #define read(a,b,c) _dxl_os2_recv(a,b,c,0)
64 #endif
65 
66 #include "dxlP.h"
67 
68 typedef int (*DXLPacketPredicate)(DXLConnection *, DXLEvent *, void *);
69 
70 static int _dxl_ReadFromSocket(DXLConnection *conn);
71 static int _dxl_WaitForReadable(DXLConnection *conn);
72 static int _dxl_IsReadable(DXLConnection *conn);
73 static void PrintEvent(DXLEvent *e);
74 
75 static DXLError DXLGetPacket(DXLConnection *, DXLPacketTypeEnum, int,
76                 DXLEvent *, int,
77                 DXLPacketPredicate, const void *);
78 
79 #define STRLEN(A) (A ? strlen(A) : 0)
80 
81 char *_DXLPacketTypes[] =
82 {
83     NULL,
84     "$int",             /* PACK_INTERRUPT */
85     "$sys",             /* PACK_SYSTEM */
86     "$ack",             /* PACK_ACK */
87     "$mac",             /* PACK_MACRODEF */
88     "$for",             /* PACK_FOREGROUND */
89     "$bac",             /* PACK_BACKGROUND */
90     "$err",             /* PACK_ERROR */
91     "$mes",             /* PACK_MESSAGE */
92     "$inf",             /* PACK_INFO */
93     "$lin",             /* PACK_LINQUIRY */
94     "$lre",             /* PACK_LRESPONSE */
95     "$dat",             /* PACK_LDATA */
96     "$sin",             /* PACK_SINQUIRY */
97     "$sre",             /* PACK_SRESPONSE */
98     "$dat",             /* PACK_SDATA */
99     "$vin",             /* PACK_VINQUIRY */
100     "$vre",             /* PACK_VRESPONSE */
101     "$dat",             /* PACK_VDATA */
102     "$com",             /* PACK_COMPLETE */
103     "$imp",             /* PACK_IMPORT */
104     "$imi",             /* PACK_IMPORTINFO */
105     "$lnk"              /* PACK_LINK */
106 };
107 
108 int _DXLNumPackets = (sizeof(_DXLPacketTypes)/sizeof(_DXLPacketTypes[0]));
109 
110 DXLEvent*
DXLNewEvent(int serialId,DXLPacketTypeEnum ptype,const char * msg)111 DXLNewEvent(int serialId, DXLPacketTypeEnum ptype, const char *msg)
112 {
113     int msgsize = 0;
114 
115     DXLEvent *event = (DXLEvent*)malloc(sizeof(DXLEvent));
116     if (!event)
117         return NULL;
118 
119     event->serial = serialId;
120     event->type = ptype;
121     if (msg) {
122         msgsize = strlen(msg) + 1;
123         if (msgsize > DXL_EVENT_BUF_SIZE)
124             event->contents = malloc(msgsize*sizeof(char));
125         else
126             event->contents = event->buffer;
127         strcpy(event->contents,msg);
128     } else {
129         event->contents = event->buffer;
130         event->buffer[0] = '\0';
131     }
132     event->contentsSize = msgsize;
133     event->next = NULL;
134     return event;
135 }
136 
137 DXLError
DXLClearEvent(DXLEvent * event)138 DXLClearEvent(DXLEvent *event)
139 {
140     if (event->contents && event->contents != event->buffer)
141         free(event->contents);
142     event->next = NULL;
143     event->contentsSize = 0;
144     event->buffer[0] = '\0';
145     event->contents = event->buffer;
146     return OK;
147 }
148 DXLError
DXLFreeEvent(DXLEvent * event)149 DXLFreeEvent(DXLEvent *event)
150 {
151     if (DXLClearEvent(event))
152         free(event);
153     return OK;
154 }
155 DXLError
DXLCopyEvent(DXLEvent * dst,DXLEvent * src)156 DXLCopyEvent(DXLEvent *dst, DXLEvent *src)
157 {
158     if (src->contentsSize > DXL_EVENT_BUF_SIZE)
159         dst->contents = malloc(src->contentsSize);
160     else
161         dst->contents = dst->buffer;
162 
163     dst->contentsSize = src->contentsSize;
164 
165     memcpy(dst->contents, src->contents, src->contentsSize);
166 
167     return OK;
168 }
169 
170 DXLError
DXLSend(DXLConnection * conn,const char * string)171 DXLSend(DXLConnection *conn, const char *string)
172 {
173     DXLPacketTypeEnum ptype=PACK_FOREGROUND;
174 
175     if (conn->dxuiConnected) {
176 	if (conn->majorVersion <= 2)
177 	    ptype = PACK_FOREGROUND;
178 	else
179 	    ptype = PACK_LINK;
180 	return DXLSendPacket(conn, ptype, string) >= 0 ? OK : ERROR;
181     }
182     else if (conn->macroDef)
183     {
184 	DXLSendUnpacketized(conn, string);
185 	return OK;
186     }
187     else
188     {
189 	ptype = PACK_FOREGROUND;
190 	return DXLSendPacket(conn, ptype, string) >= 0 ? OK : ERROR;
191     }
192 
193 }
194 
195 
196 #ifdef DEBUG_MESSAGES
197 static int first = 1;
198 static FILE *dbg = NULL;
199 #endif
200 
201 int     /* packet id that was sent, -1 on error */
DXLSendPacket(DXLConnection * conn,DXLPacketTypeEnum ptype,const char * string)202 DXLSendPacket(DXLConnection *conn, DXLPacketTypeEnum ptype, const char *string)
203 {
204     int l = STRLEN(string);
205     char *buffer = malloc(l + 50);
206     int packetId, sts     = 0;
207     int written = 0;
208 
209     if (!conn || conn->fd < 0 || (ptype > _DXLNumPackets) || (ptype <= 0))
210         return ERROR;
211 
212     packetId = conn->id++;
213 
214 
215     if (ptype == PACK_MACRODEF)
216         l = SPRINTF(buffer,"|%d|%s|0|\n", packetId, _DXLPacketTypes[ptype]);
217     else if (ptype == PACK_INTERRUPT)
218     {
219         l = SPRINTF(buffer,"|%d|%s|1|0|\n", packetId, _DXLPacketTypes[ptype]);
220     }
221     else if (l == 0)
222         l = SPRINTF(buffer,"|%d|%s|0||\n", packetId, _DXLPacketTypes[ptype]);
223     else
224         l = SPRINTF(buffer,
225             "|%d|%s|%d|%s|\n", packetId, _DXLPacketTypes[ptype], l, string);
226 
227 #ifdef DEBUG_MESSAGES
228     if (first)
229     {
230 	first = 0;
231 	dbg = fopen("debug", "w");
232     }
233     else
234 	dbg = fopen("debug", "a");
235 
236     fprintf(dbg, "--> %s", buffer);
237     fclose(dbg);
238 #endif
239 
240     do {
241         if (_dxl_ReadFromSocket(conn) < 0)
242         {
243             sts = -1;
244             break;
245         }
246         if ((sts == 0) &&  conn->debugMessaging)
247             fprintf(stderr, "Sending -> %s\n",buffer);
248         sts = write(conn->fd, buffer + written, l);
249         l -= sts;
250         written += sts;
251     }
252     while (sts > 0 && l > 0);
253 
254     free(buffer);
255     if (sts < 0) {
256         _dxl_InvalidateSocket(conn);
257 	packetId = -1;
258 	goto done;
259     } else if (ptype != PACK_MACRODEF && conn->synchronous) {
260         if (!DXLSync(conn)) {
261 	    packetId = -1;
262 	    goto done;
263 	}
264     }
265 
266 done:
267 
268     return packetId;
269 }
270 
271 
272 int
DXLQuery(DXLConnection * conn,const char * string,const int length,char * result)273 DXLQuery(DXLConnection *conn, const char *string,
274          const int length, char *result)
275 {
276     int found;
277     int requestId;
278     DXLEvent    event;
279     DXLPacketTypeEnum ptype;
280 
281 
282     if (conn->fd < 0)
283         goto error;
284 
285 
286     if (conn->dxuiConnected)
287     {
288         if (conn->majorVersion <= 2)
289             ptype = PACK_FOREGROUND;
290         else
291             ptype = PACK_LINK;
292     }
293     else
294     {
295         /*
296          * FIXME: This probably is not the correct code,
297          * but it serves as a marker.
298          */
299         ptype = PACK_FOREGROUND;
300 
301         fprintf(stderr,"DXLQuery() not implemented for dexec connections\n");
302         goto error;
303     }
304 
305     requestId = DXLSendPacket(conn,ptype,string);
306     if (requestId < 0)
307         goto error;
308 
309     found = 0;
310     if (conn->dxuiConnected)  {
311         if (DXLGetPacketId(conn, PACK_LRESPONSE, requestId, &event))
312             found = 1;
313     } else {
314         /* include "filename" causes completes to come back that match
315          * the zero'th sync
316          */
317         if (DXLGetPacketId(conn, PACK_COMPLETE, 0, &event))
318             found =  1;
319     }
320 
321     if (!found)
322     {
323         _dxl_InvalidateSocket(conn);
324         DXLClearEvent(&event);
325         goto error;
326     }
327 
328     strncpy(result, event.contents, length);
329 
330     DXLClearEvent(&event);
331 
332     return length;
333 
334 error:
335     return -1;
336 }
337 
RemoveEvent(DXLConnection * conn,DXLEvent * e)338 static void RemoveEvent(DXLConnection *conn, DXLEvent *e)
339 {
340     DXLEvent *event, *last_event = NULL;
341 
342     for (event = conn->events; event ; event = event->next) {
343         if (event == e)
344             break;
345         last_event = event;
346     }
347 
348     if (event == e) {
349         if (e == conn->events) {
350             /*
351              * First item on list
352              */
353             conn->events = e->next;
354             if (e == conn->lastEvent)   /* ...and last item */
355                 conn->lastEvent = NULL;
356         } else if (e == conn->lastEvent) {
357             /*
358              * Last item on list
359              */
360             conn->lastEvent = last_event;
361             last_event->next = NULL;
362         } else {
363             /*
364              * Middle item on list
365              */
366             last_event->next = e->next;
367         }
368     }
369 
370     conn->nEvents--;
371 }
AppendEvent(DXLConnection * conn,DXLEvent * e)372 static void AppendEvent(DXLConnection *conn, DXLEvent *e)
373 {
374     if (conn->events == NULL) {
375         conn->events = e;
376     } else {
377         conn->lastEvent->next = e;
378     }
379     conn->lastEvent = e;
380     conn->nEvents++;
381     e->next = NULL;     /* Just to be sure */
382 
383     /*
384      * We've pulled an event off the socket and onto the local queue.
385      * If the event handler is dependent on a select() on the socket to
386      * determine that there's something to do, it won't find anything.
387      * So we install an idle-time event processor that will check for
388      * something to do when the system is otherwise idle.
389      */
390     _dxf_InstallIdleEventHandler(conn);
391 }
392 
393 
394 DXLError
DXLNextPacket(DXLConnection * conn,DXLEvent * event)395 DXLNextPacket(DXLConnection *conn, DXLEvent *event)
396 {
397     while(conn->nEvents == 0)
398     {
399         _dxl_WaitForReadable(conn);
400         if (_dxl_ReadFromSocket(conn) == 0)
401             return ERROR;
402     }
403 
404     if (conn->events->type == PACK_ERROR)
405         _DXLError(conn, conn->events->contents);
406 
407     DXLCopyEvent(event, conn->events);
408 
409     RemoveEvent(conn, conn->events);
410     DXLFreeEvent(conn->events);
411 
412     return OK;
413 }
414 
415 int
DXLWaitForEvent(DXLConnection * conn)416 DXLWaitForEvent(DXLConnection *conn)
417 {
418     if(conn->nEvents == 0)
419 	_dxl_WaitForReadable(conn);
420     return OK;
421 }
422 
423 
424 
DXLDispatchEvent(DXLConnection * conn,DXLEvent * e)425 static void DXLDispatchEvent(DXLConnection *conn, DXLEvent *e)
426 {
427     RemoveEvent(conn,e);
428     if (conn->debugMessaging) {
429         fprintf(stderr, "Dispatching <- ");
430         PrintEvent(e);
431     }
432     _dxl_HandleMessage(conn, e->type, e->serial, e->contents);
433 }
434 
435 DXLError
DXLProcessEventList(DXLConnection * conn)436 DXLProcessEventList(DXLConnection *conn)
437 {
438     DXLEvent *e;
439 
440     while (_dxl_IsReadable(conn))
441         if (_dxl_ReadFromSocket(conn) == 0)
442             return ERROR;
443 
444     while (NULL != (e = conn->events))
445     {
446         DXLDispatchEvent(conn,e);
447         DXLFreeEvent(e);
448     }
449 
450     conn->nEvents = 0;
451 
452     /*
453      * Now we have cleared all the input from both the socket and the
454      * input queue in conn, so we don't need an idle-time input check.
455      */
456     _dxf_ClearIdleEventHandler(conn);
457 
458     return OK;
459 }
460 
461 
462 /*
463  * Starting with the given event, search the event list for the event
464  * matching the given type and requestId.  If requestId is < 0 then we
465  * don't try and match the requestId.  Further, if pp is not NULL then
466  * we also try and match the event with a call to (pp)(conn,event,arg).
467  *
468  */
469 static DXLEvent*
DXLFindEventInList(DXLConnection * conn,DXLEvent * event,DXLPacketTypeEnum type,int requestId,DXLPacketPredicate pp,const void * arg)470 DXLFindEventInList(DXLConnection *conn, DXLEvent *event,
471                 DXLPacketTypeEnum type, int requestId,
472                 DXLPacketPredicate pp, const void *arg)
473 {
474     DXLEvent *e;
475 
476     for (e=event ; e ; ) {
477         if ((e->type == type) &&
478             ((requestId < 0) || (e->serial == requestId)) &&
479             (!pp || (pp)(conn,e,(char *)arg)))
480             break;
481         e = e->next;
482     }
483     return e;
484 }
485 
486 /*
487  * Get the packet specified by the given packet type and the given id.
488  * If id is <= 0, then we don't try and match the ids with packets.
489  * If pp is not NULL, then we call it on the event (pp(conn,e,arg)),
490  * to see if it is a match.
491  * If we find an event with a match, given the above criteria, then
492  * we copy the event into the user structure .
493  */
494 static int
DXLCheckPacket(DXLConnection * conn,DXLPacketTypeEnum type,int requestId,DXLEvent * event,DXLPacketPredicate pp,const void * arg)495 DXLCheckPacket(DXLConnection *conn, DXLPacketTypeEnum type, int requestId,
496                 DXLEvent *event, DXLPacketPredicate pp, const void *arg)
497 {
498     DXLEvent *e;
499 
500     e = DXLFindEventInList(conn,conn->events,type,requestId, pp, arg);
501     if (e) {
502         DXLCopyEvent(event, e);
503         return 1;
504     }
505     return 0;
506 }
507 /*
508  * Get the packet specified by the given packet type and the given id.
509  * If id is <= 0, then we don't try and match the ids with packets.
510  * If pp is not NULL, then we call it on the event (pp(conn,e,arg)),
511  * to see if it is a match.
512  * If we find an event with a match, given the above criteria, then
513  * we copy the event into the user structure and if 'remove' is non-zero
514  * we remove the event from the event list.
515  */
516 static DXLError
DXLGetPacket(DXLConnection * conn,DXLPacketTypeEnum type,int requestId,DXLEvent * event,int remove,DXLPacketPredicate pp,const void * arg)517 DXLGetPacket(DXLConnection *conn, DXLPacketTypeEnum type, int requestId,
518                 DXLEvent *event, int remove,
519                 DXLPacketPredicate pp, const void *arg)
520 {
521     DXLEvent *e;
522 
523     e = DXLFindEventInList(conn,conn->events,type,requestId, pp, arg);
524 
525     while (!e)
526     {
527         e = conn->lastEvent;
528 
529         if (! _dxl_WaitForReadable(conn))
530             return ERROR;
531 
532         if (! _dxl_ReadFromSocket(conn))
533             return ERROR;
534 
535         if (!e)
536           e = conn->events;
537         else
538           e = e->next;
539 #if 0
540         PrintEventList(e); fprintf(stderr, "\n");
541 #endif
542         e = DXLFindEventInList(conn,e,type,requestId, pp, arg);
543     }
544 
545     DXLCopyEvent(event, e);
546 
547     if (remove) {
548         RemoveEvent(conn, e);
549         DXLFreeEvent(e);
550     }
551 
552     return OK;
553 }
554 
MatchString(DXLConnection * conn,DXLEvent * e,void * arg)555 static int MatchString(DXLConnection *conn, DXLEvent *e, void *arg)
556 {
557     char *str = (char*)arg;
558 
559     if (!str || strstr(e->contents,str))
560         return 1;
561     else
562         return 0;
563 }
564 /*
565  * Find and read until a packet with the given type, packet id, and string
566  * contained in the message is found.  This may block on the socket.
567  * Return the found event in the given event, and remove the event
568  * from the event list.
569  */
570 DXLError
DXLGetPacketIdString(DXLConnection * conn,DXLPacketTypeEnum type,int requestId,const char * str,DXLEvent * event)571 DXLGetPacketIdString(DXLConnection *conn, DXLPacketTypeEnum type,
572                 int requestId, const char *str, DXLEvent *event)
573 {
574     return DXLGetPacket(conn,type, requestId,event, 1, MatchString,str);
575 }
576 /*
577  * Find and read until a packet with the given type and string
578  * contained in the message is found.  This may block on the socket.
579  * Return the found event in the given event, and remove the event
580  * from the event list.
581  */
582 DXLError
DXLGetPacketString(DXLConnection * conn,DXLPacketTypeEnum type,const char * str,DXLEvent * event)583 DXLGetPacketString(DXLConnection *conn, DXLPacketTypeEnum type,
584                 const char *str, DXLEvent *event)
585 {
586     return DXLGetPacket(conn,type,-1,event, 1, MatchString,str);
587 }
588 /*
589  * Find a packet in the current event list with the given type and string
590  * contained in the message.  Do not block on the socket.
591  * Return the found event in the given event, and do not remove the event
592  * from the event list.  Return 0 if a matching packet was not found,
593  * otherwise non-zero.
594  */
595 int
DXLCheckPacketString(DXLConnection * conn,DXLPacketTypeEnum type,const char * str,DXLEvent * event)596 DXLCheckPacketString(DXLConnection *conn, DXLPacketTypeEnum type,
597                 const char *str, DXLEvent *event)
598 {
599     return DXLCheckPacket(conn,type,-1,event, MatchString,str);
600 }
601 /*
602  * Find and read until a packet with the given type and  string contained
603  * in the message is found.
604  * Return the found event in the given event, and do not remove the event
605  * from the event list.
606  */
607 DXLError
DXLWaitPacketString(DXLConnection * conn,DXLPacketTypeEnum type,const char * str,DXLEvent * event)608 DXLWaitPacketString(DXLConnection *conn, DXLPacketTypeEnum type,
609                 const char *str, DXLEvent *event)
610 {
611     return DXLGetPacket(conn,type,-1,event, 0, MatchString,str);
612 }
613 /*
614  * Find and read until a packet with the given type and  id is found.
615  * Return the found event in the given event, and remove the event
616  * from the event list.
617  */
618 DXLError
DXLGetPacketId(DXLConnection * conn,DXLPacketTypeEnum type,int id,DXLEvent * event)619 DXLGetPacketId(DXLConnection *conn, DXLPacketTypeEnum type, int id,
620                                 DXLEvent *event)
621 {
622     return DXLGetPacket(conn,type,id,event, 1, NULL,NULL);
623 }
624 
625 
626 DXLError
DXLPeekPacket(DXLConnection * conn,DXLEvent * event)627 DXLPeekPacket(DXLConnection *conn, DXLEvent *event)
628 {
629     if (conn->nEvents == 0)
630         _dxl_ReadFromSocket(conn);
631 
632     if (conn->nEvents == 0)
633         return ERROR;
634 
635     DXLCopyEvent(event, conn->events);
636 
637     return OK;
638 }
639 
640 static int
_dxl_IsReadable(DXLConnection * conn)641 _dxl_IsReadable(DXLConnection *conn)
642 {
643 #ifndef OS2
644     fd_set fds;
645 #endif
646 #ifdef hp700
647     int width = MAXFUPLIM;
648 #else
649 #ifdef aviion
650     int width = NOFILE;
651 #else
652 #ifdef solaris
653     int width = FD_SETSIZE;
654 #else
655 #ifdef DXD_HAS_WINSOCKETS
656     int width = FD_SETSIZE;
657 #else
658 #ifndef OS2
659     int width = getdtablesize();
660 #endif
661 #endif
662 #endif
663 #endif
664 #endif
665     int retval = 0;
666 
667     struct timeval to;
668 
669     if (conn->fd < 0)
670 	return 0;
671 
672 #if  !defined(OS2)  && !defined(DXD_HAS_WINSOCKETS)
673     FD_ZERO(&fds);
674     FD_SET(conn->fd, &fds);
675     to.tv_sec = 0;
676     to.tv_usec = 0;
677 
678     /* this will restart select if it has been interrupted by a signal */
679 	SELECT_INTR((conn->fd + 1), (SELECT_ARG_TYPE *)&fds, NULL, NULL, &to, retval);
680 #endif
681 
682 #ifdef OS2
683     retval = select(&conn->fd, 1, 0, 0, 0);
684 #endif
685 
686 #ifdef DXD_HAS_WINSOCKETS
687     to.tv_sec = 0;
688     to.tv_usec = 0;
689     FD_ZERO(&fds);
690     FD_SET(conn->fd, &fds);
691     retval =  select(conn->fd, &fds, NULL, NULL, &to);
692 #endif
693 
694     if (retval > 0) return TRUE;
695     if (retval == 0) return FALSE;
696 
697     /* retval < 0 */
698     _dxl_InvalidateSocket (conn);
699     return FALSE;
700 }
701 
702 int
DXLIsMessagePending(DXLConnection * conn)703 DXLIsMessagePending(DXLConnection *conn)
704 {
705     return (conn->nEvents > 0) || _dxl_IsReadable(conn);
706 }
707 
708 
709 static int
_dxl_WaitForReadable(DXLConnection * conn)710 _dxl_WaitForReadable(DXLConnection *conn)
711 {
712     int retval;
713 #ifndef OS2
714     fd_set fds;
715 #endif
716 #ifdef hp700
717     int    width = MAXFUPLIM;
718 #else
719 #ifdef aviion
720     int    width = NOFILE;
721 #else
722 #ifdef solaris
723     int    width = FD_SETSIZE;
724 #else
725 #ifdef DXD_HAS_WINSOCKETS
726     int    width = FD_SETSIZE;
727 #else
728 #ifndef OS2
729     int    width = getdtablesize();
730 #endif
731 #endif
732 #endif
733 #endif
734 #endif
735 
736     if (conn->fd < 0)
737 	return 0;
738 
739 #if  !defined(OS2)  && !defined(DXD_HAS_WINSOCKETS)
740     FD_ZERO(&fds);
741     FD_SET(conn->fd, &fds);
742 
743     /* this will restart select if it was interrupted by a signal */
744 	SELECT_INTR((conn->fd + 1), (SELECT_ARG_TYPE *)&fds, NULL, NULL, NULL, retval);
745     if(retval < 0)
746         goto error;
747 #endif
748 
749 #ifdef OS2
750     if (select(&conn->fd, 1, 0, 0, -1)<0)
751         goto error;
752 #endif
753 
754 #ifdef DXD_HAS_WINSOCKETS
755     FD_ZERO(&fds);
756     FD_SET(conn->fd, &fds);
757 	width =  select((conn->fd + 1), &fds, NULL, NULL, NULL);
758     if (width < 0)
759         goto error;
760 
761 #endif
762     return 1;
763 
764 error:
765    _dxl_InvalidateSocket(conn);
766     return 0;
767 }
768 
769 #if 0
770 static int lock_me = 0;
771 #endif
772 
773 static int
_dxl_ReadFromSocket(DXLConnection * conn)774 _dxl_ReadFromSocket(DXLConnection *conn)
775 {
776     int    id, typei;
777     char   type[8];
778     int    nbytes;
779 
780     char   *start;
781     int    nRemaining;
782 
783     char   *buffer;
784     char   *msgbuf;
785     int    bufSize = 4096;
786     int    mbufSize = 4096;
787 
788     if (conn->fd < 0)
789 	return 0;
790 
791     buffer = (char*) malloc(bufSize);
792     msgbuf = (char*) malloc(mbufSize);
793 
794     while (_dxl_IsReadable(conn)) {
795 	int nread;
796 
797 	nRemaining = conn->nLeftOver;
798 
799 	while( nRemaining+1025 > bufSize ){
800 	   char* tmp = buffer;
801 	   bufSize *= 2;
802 	   buffer = (char*) malloc( bufSize );
803 	   free(tmp);
804 	}
805 
806         if (nRemaining) {
807 	    memcpy (buffer, conn->leftOver, nRemaining);
808             nread = read(conn->fd, buffer+nRemaining, 1024);
809         } else {
810             nread = read(conn->fd, buffer, 1024);
811         }
812 	if (nread <= 0)
813 	    goto error;
814 	nRemaining+= nread;
815 	buffer[nRemaining] = '\0';
816 
817         start = buffer;
818 	/*
819 	 * We used to check done here, but now we'll just keep reading
820 	 * from start until there isn't anything left to read.
821 	 */
822         while (1) {
823             int len, items;
824 	    DXLEvent *event;
825 
826 	    int msgbytes_in_buffer;
827 	    int bytes_used;
828 	    short message_completed;
829 
830 	    /*
831 	     * sscanf() leaves 'len' unset if the last '|' was not seen
832 	     */
833 	    len = -1;
834 	    items = sscanf(start, "|%d|%[^|]|%d|%n", &id, type, &nbytes, &len);
835 	    /*
836 	     * Perform 2 checks to see if we have enough bytes in the buffer
837 	     * to form a complete message.  First check to see if the sscanf
838 	     * completed.  Then check to see if the number of bytes resulting
839 	     * completes a message.  In order to complete a message it has
840 	     * to get the trailing |\n.
841 	     */
842             if ((items != 3) || (len == -1)) {
843 		message_completed = 0;
844             } else {
845 		msgbytes_in_buffer = nRemaining - len;
846 		if ((nbytes+2) > msgbytes_in_buffer) {
847 		    message_completed = 0;
848 		} else {
849 		    message_completed = 1;
850 		}
851 	    }
852 	    if (!message_completed) {
853 		if (nRemaining >= conn->allocdLeftOver) {
854 		    free(conn->leftOver);
855 		    /* malloc 1.5 times nRemaining rounded to the nearest 16 */
856 		    conn->allocdLeftOver = 16 + ((nRemaining + (nRemaining>>1)) & (~15));
857 		    conn->leftOver = malloc(conn->allocdLeftOver);
858 		    if (!conn->leftOver)
859 			goto error;
860 		}
861 
862 
863 		strncpy(conn->leftOver, start, nRemaining);
864 		conn->nLeftOver = nRemaining;
865 		break;
866 	    }
867 
868 	    for (typei = 1; typei < _DXLNumPackets; typei++)
869 		if (! strcmp(type, _DXLPacketTypes[typei]))
870 		    break;
871 
872 	    if (typei == _DXLNumPackets) {
873 		fprintf (stderr, "%s[%d] packet error\n", __FILE__,__LINE__);
874 		goto error;
875 	    }
876 
877 	    bytes_used = (len + nbytes + 2);   /* 2 = "|\n" */
878 
879 	    while( nbytes+2 > mbufSize ){
880 	       char* tmp = msgbuf;
881 	       mbufSize *= 2;
882 	       msgbuf = (char*) malloc( mbufSize );
883 	       free(tmp);
884 	    }
885 
886 	    strncpy(msgbuf, start+len, nbytes + 2);
887 	    if (bytes_used > nRemaining)
888 		goto error;
889 
890 	    if (msgbuf[nbytes] != '|') {
891 		fprintf (stderr, "%s[%d]packet error\n", __FILE__,__LINE__);
892 		goto error;
893 	    }
894 
895 	    nRemaining -= bytes_used;
896 	    start += bytes_used;
897 
898 	    msgbuf[nbytes] = '\0';
899 
900 	    event = DXLNewEvent(id, (DXLPacketTypeEnum) typei,msgbuf);
901 	    if (!event)
902 		goto error;
903 	    if (conn->debugMessaging) {
904 		fprintf(stderr, "Recving <- ");
905 		PrintEvent(event);
906 	    }
907 	    AppendEvent(conn,event);
908         }
909     }
910 
911     free(buffer);
912     free(msgbuf);
913 
914     return 1;
915 
916 error:
917 
918     free(buffer);
919     free(msgbuf);
920 
921    _dxl_InvalidateSocket(conn);
922     return 0;
923 }
924 
DXLSendUnpacketized(DXLConnection * conn,const char * string)925 DXLError DXLSendUnpacketized(DXLConnection *conn, const char *string)
926 {
927     int length, r;
928     char *newString;
929 
930     if (conn->fd < 0)
931         return ERROR;
932 
933     length = STRLEN(string) + 1;
934     newString = malloc((length + 1) * sizeof(char));
935     strcpy(newString, string);
936     newString[length-1] = '\n';
937     newString[length]   = '\0';
938 
939     if (conn->debugMessaging)
940         fprintf(stderr, "Sending -> %s", newString);
941 
942 
943 #ifdef DEBUG_MESSAGES
944     if (first)
945     {
946 	first = 0;
947 	dbg = fopen("debug", "w");
948     }
949     else
950 	dbg = fopen("debug", "a");
951 
952     fprintf(dbg, "Unpacketized --> %s", newString);
953 
954     fclose(dbg);
955 #endif
956 
957     if (write(conn->fd, newString, length) != length)
958         r = ERROR;
959     else
960         r = OK;
961 
962     free(newString);
963     return r;
964 }
965 
DXLSendImmediate(DXLConnection * conn,const char * string)966 DXLError DXLSendImmediate(DXLConnection *conn, const char *string)
967 {
968     int length, r;
969     char *newString;
970 
971     if (conn->fd < 0)
972         return ERROR;
973 
974     length = STRLEN(string) + 1;
975     newString = malloc((length + 1) * sizeof(char));
976 
977     strcpy(newString, "$");
978     strcat(newString, string);
979 
980     r = DXLSendUnpacketized(conn,newString);
981 
982     if (r == OK && conn->synchronous)
983         DXLSync(conn);
984 
985     free(newString);
986 
987     return r;
988 }
989 
990 DXLError
DXLHandlePendingMessages(DXLConnection * conn)991 DXLHandlePendingMessages(DXLConnection *conn)
992 {
993 
994    DXLProcessEventList(conn);
995    while (_dxl_IsReadable(conn))
996    {
997        _dxl_ReadFromSocket(conn);
998        DXLProcessEventList(conn);
999    }
1000 
1001    return OK;
1002 }
PrintEvent(DXLEvent * e)1003 static void PrintEvent(DXLEvent *e)
1004 {
1005     fprintf(stderr, "id %d type %d %s\n", e->serial, e->type, e->contents);
1006 }
1007 
DXLSetMessageDebugging(DXLConnection * conn,int on)1008 int  DXLSetMessageDebugging(DXLConnection *conn, int on)
1009 {
1010     int oldval = conn->debugMessaging;
1011     conn->debugMessaging = on;
1012     return oldval;
1013 }
1014 
1015 /* DW D Watson added to end of file */
1016 
1017 DXLError
exDXLBeginMacroDefinition(DXLConnection * conn,const char * mhdr)1018 exDXLBeginMacroDefinition(DXLConnection *conn, const char *mhdr)
1019 {
1020     int sts = 0;
1021     DXLPacketTypeEnum ptype;
1022 
1023     if (conn->dxuiConnected)
1024     {
1025         return ERROR;
1026     }
1027     else
1028     {
1029         conn->macroDef = TRUE;
1030         ptype = PACK_MACRODEF;
1031         sts = DXLSendPacket(conn,ptype,0);
1032         if (sts < 0)
1033           return ERROR;
1034         DXLSendUnpacketized(conn, mhdr);
1035         DXLSendUnpacketized(conn, "{\n");
1036 
1037     }
1038     return OK;
1039 
1040 }
1041 
1042 DXLError
exDXLEndMacroDefinition(DXLConnection * conn)1043 exDXLEndMacroDefinition(DXLConnection *conn)
1044 {
1045     int sts = 0;
1046 
1047     if (conn->dxuiConnected)
1048     {
1049         return ERROR;
1050     }
1051     else
1052     {
1053         if (!conn->macroDef) {
1054           fprintf(stderr,"exDXLEndMacroDefinition: not valid before exDXLBeginMacroDefinition()\n");
1055           return ERROR;
1056         } /* endif */
1057         conn->macroDef = FALSE;
1058         sts = DXLSendUnpacketized(conn,"}\n|\n");
1059         if (sts < 0)
1060           return ERROR;
1061 
1062     }
1063 
1064     if (conn->synchronous)
1065         if (!DXLSync(conn))
1066             return ERROR;
1067 
1068     return OK;
1069 }
1070