1 /*
2  * Copyright 1993 Network Computing Devices, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name Network Computing Devices, Inc. not be
9  * used in advertising or publicity pertaining to distribution of this
10  * software without specific, written prior permission.
11  *
12  * THIS SOFTWARE IS PROVIDED 'AS-IS'.  NETWORK COMPUTING DEVICES, INC.,
13  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
14  * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15  * PARTICULAR PURPOSE, OR NONINFRINGEMENT.  IN NO EVENT SHALL NETWORK
16  * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
17  * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
18  * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
19  * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  *
22  * $Id: Alibint.c 246 2007-05-12 01:03:53Z jon $
23  * $NCDId: @(#)Alibint.c,v 1.28 1995/12/28 19:42:47 greg Exp $
24  */
25 
26 /* Portions derived from */
27 /*
28  * $XConsortium: XlibInt.c,v 11.163 92/07/24 17:34:55 rws Exp $
29  */
30 
31 /* Copyright    Massachusetts Institute of Technology    1985, 1986, 1987 */
32 
33 /*
34 Permission to use, copy, modify, distribute, and sell this software and its
35 documentation for any purpose is hereby granted without fee, provided that
36 the above copyright notice appear in all copies and that both that
37 copyright notice and this permission notice appear in supporting
38 documentation, and that the name of M.I.T. not be used in advertising or
39 publicity pertaining to distribution of the software without specific,
40 written prior permission.  M.I.T. makes no representations about the
41 suitability of this software for any purpose.  It is provided "as is"
42 without express or implied warranty.
43 */
44 
45 /*
46  *	AlibInt.c - Internal support routines for the C subroutine
47  *	interface library (audiolib) to the NCD-AUDIO Protocol V1.0.
48  */
49 
50 #include "release.h"
51 
52 #if defined(__CYGWIN__)
53 #include <asm/socket.h>
54 #include <arpa/inet.h>
55 #endif
56 
57 #include <audio/Alibint.h>
58 #include <audio/Aos.h>
59 #include "Alibnet.h"
60 #include <stdio.h>
61 #ifndef WIN32
62 #ifdef SYSV	/* fd_set */
63 #include <sys/socket.h>
64 #endif
65 #include <sys/time.h>
66 #endif /* !WIN32 */
67 
68 /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
69  * systems are broken and return EWOULDBLOCK when they should return EAGAIN
70  */
71 #ifndef WIN32
72 #if defined(EAGAIN) && defined(EWOULDBLOCK)
73 #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
74 #else
75 #ifdef EAGAIN
76 #define ETEST(err) (err == EAGAIN)
77 #else
78 #define ETEST(err) (err == EWOULDBLOCK)
79 #endif
80 #endif
81 #else /* WIN32 */
82 #define ETEST(err) (WSAGetLastError() == WSAEWOULDBLOCK)
83 #endif /* WIN32 */
84 
85 #ifdef LACHMAN
86 #ifdef EMSGSIZE
87 #undef EMSGSIZE
88 #endif
89 #define EMSGSIZE ERANGE
90 #endif
91 
92 #ifdef MUSTCOPY
93 
94 #define STARTITERATE(tpvar,type,start,endcond) \
95   { char *cpvar; \
96   for (cpvar = (char *) (start); endcond; ) { \
97     type dummy; bcopy (cpvar, (char *) &dummy, SIZEOF(type)); \
98     tpvar = &dummy;
99 #define ITERPTR(tpvar) cpvar
100 #define RESETITERPTR(tpvar,type,start) cpvar = start
101 #define INCITERPTR(tpvar,type) cpvar += SIZEOF(type)
102 #define ENDITERATE }}
103 
104 #else
105 
106 #define STARTITERATE(tpvar,type,start,endcond) \
107   for (tpvar = (type *) (start); endcond; )
108 #define ITERPTR(tpvar) (char *)tpvar
109 #define RESETITERPTR(tpvar,type,start) tpvar = (type *) (start)
110 #define INCITERPTR(tpvar,type) tpvar++
111 #define ENDITERATE
112 
113 #endif /* MUSTCOPY */
114 
115 typedef union {
116     auReply rep;
117     char buf[BUFSIZE];
118 } _AuAlignedBuffer;
119 
120 static char *_AuAsyncReply (
121                             AuServer *,		/* server */
122                             auReply *,		/* rep */
123                             char *,		/* buf */
124                             int *, 		/* lenp */
125                             AuBool		/* discard */
126 );
127 
128 static void _AuEnq(AuServer *,	/* server */
129                    auEvent *,   /* event */
130                    int		/* who */
131 
132 );
133 
134 static void _AuEventEnqueued(
135                              AuServer *,			/* server */
136                              int,			/* who */
137                              AuEvent *			/* event */
138 );
139 
140 /*
141  * The following routines are internal routines used by audiolib for protocol
142  * packet transmission and reception.
143  *
144  * _AuIOError(AuServer *) will be called if any sort of system call error occurs.
145  * This is assumed to be a fatal condition, i.e., AuIOError should not return.
146  *
147  * _AuError(AuServer *, auError *) will be called whenever an Au_Error event is
148  * received.  This is not assumed to be a fatal condition, i.e., it is
149  * acceptable for this procedure to return.  However, AuError should NOT
150  * perform any operations (directly or indirectly) on the DISPLAY.
151  *
152  * Routines declared with a return type of 'AuStatus' return 0 on failure,
153  * and non 0 on success.  Routines with no declared return type don't
154  * return anything.  Whenever possible routines that create objects return
155  * the object they have created.
156  */
157 
158 
159 /* this is a mutex for _AuReadEvents() */
160 static _AuMutex _rev_mutex = _AU_MUTEX_INITIALIZER;
161 
162 static int padlength[4] = {0, 3, 2, 1};
163     /* lookup table for adding padding bytes to data that is read from
164     	or written to the Au socket.  */
165 
166 static auReq _dummy_request = {
167 	0, 0, 0
168 };
169 
170 /*
171  * This is an OS dependent routine which:
172  * 1) returns as soon as the connection can be written on....
173  * 2) if the connection can be read, must enqueue events and handle errors,
174  * until the connection is writable.
175  */
176 static void
_AuWaitForWritable(AuServer * aud)177 _AuWaitForWritable(AuServer *aud)
178 {
179 #if !defined(AMOEBA) && !defined(_MINIX)
180 #ifndef WIN32
181     fd_set r_mask;
182     fd_set w_mask;
183     int nfound;
184 
185     FD_ZERO(&r_mask);
186     FD_ZERO(&w_mask);
187 
188     while (1) {
189 	FD_SET(aud->fd, &r_mask);
190         FD_SET(aud->fd, &w_mask);
191 
192 	do {
193 	    nfound = select (aud->fd + 1, &r_mask, &w_mask,
194 			     (fd_set *)NULL, (struct timeval *)NULL);
195 	    if (nfound < 0 && errno != EINTR)
196 		_AuIOError(aud);
197 	} while (nfound <= 0);
198 
199 	/* if (_AuANYSET(r_mask)) { */
200 	if (FD_ISSET(aud->fd,&r_mask)) {
201 #else /* WIN32 */
202     fd_set rset, wset;
203     int nfound;
204 
205     while (1)
206     {
207 	do
208 	{
209 	    FD_ZERO(&rset);
210 	    FD_ZERO(&wset);
211 	    FD_SET(aud->fd, &rset);
212 	    FD_SET(aud->fd, &wset);
213 
214 	    nfound = select(1, &rset, &wset, NULL, NULL);
215 
216 	    if (nfound < 0 && WSAGetLastError() != WSAEINTR)
217 		_AuIOError(aud);
218 	} while (nfound <= 0);
219 
220     if (FD_ISSET(aud->fd, &rset))
221     {
222 #endif /* WIN32 */
223 	    _AuAlignedBuffer buf;
224 	    int pend;
225 	    int len;
226 	    auReply *rep;
227 
228 	    /* find out how much data can be read */
229 	    if (BytesReadable(aud->fd, (char *) &pend) < 0)
230 		_AuIOError(aud);
231 	    len = pend;
232 
233 	    /* must read at least one auEvent; if none is pending, then
234 	       we'll just block waiting for it */
235 	    if (len < SIZEOF(auReply)) len = SIZEOF(auReply);
236 
237 	    /* but we won't read more than the max buffer size */
238 	    if (len > BUFSIZE) len = BUFSIZE;
239 
240 	    /* round down to an integral number of AuReps */
241 	    len = (len / SIZEOF(auReply)) * SIZEOF(auReply);
242 
243 	    _AuRead (aud, buf.buf, (AuInt32) len);
244 
245 	    STARTITERATE(rep,auReply,buf.buf,len > 0) {
246 		if (rep->generic.type == Au_Reply) {
247 		    pend = len;
248 		    RESETITERPTR(rep,auReply,
249 				 _AuAsyncReply (aud, rep,
250 					       ITERPTR(rep), &pend, AuTrue));
251 		    len = pend;
252 		} else {
253 		    if (rep->generic.type == Au_Error)
254 			_AuError (aud, (auError *)rep);
255 		    else	/* must be an event packet */
256 			_AuEnq (aud, (auEvent *)rep, AuEventEnqueuedByUnknown);
257 		    INCITERPTR(rep,auReply);
258 		    len -= SIZEOF(auReply);
259 		}
260 	    } ENDITERATE
261 	}
262 #ifndef WIN32
263 	/* if (_AuANYSET(w_mask))*/
264 	if (FD_ISSET(aud->fd, &w_mask))
265 	    return;
266 #else /* WIN32 */
267 	if (FD_ISSET(aud->fd, &wset))
268 	    return;
269 #endif /* WIN32 */
270     }
271 #else /* AMOEBA || _MINIX */
272     /* Its a fatal error when this is called under Amoeba or Minix */
273     printf(stderr, "audiolib: _AuWaitForWritable called\n");
274     abort();
275 #endif /* AMOEBA || _MINIX */
276 }
277 
278 
279 static void
280 _AuWaitForReadable(AuServer *aud)
281 {
282 #ifndef WIN32
283 #if !defined(AMOEBA) && !defined(_MINIX)
284     fd_set r_mask;
285     int result;
286 
287     FD_ZERO(&r_mask);
288     do {
289 	FD_SET(aud->fd, &r_mask);
290 	result = select(aud->fd + 1, &r_mask,
291 			(fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL);
292 	if (result == -1 && errno != EINTR) _AuIOError(aud);
293     } while (result <= 0);
294 #else /* AMOEBA || _MINIX */
295     /* Its a fatal error when this is called under Amoeba or Minix */
296     printf(stderr, "audiolib: _AuWaitForReadable called\n");
297     abort();
298 #endif /* AMOEBA || _MINIX */
299 #else /* WIN32 */
300     while (1)
301     {
302 	fd_set set;
303 
304 	FD_ZERO(&set);
305 	FD_SET(aud->fd, &set);
306 
307 	if (select(1, &set, NULL, NULL, NULL) == 1)
308 	    return;
309 
310 	if (WSAGetLastError() != WSAEINTR)
311 	    _AuIOError(aud);
312     }
313 #endif /* WIN32 */
314 }
315 
316 
317 /*
318  * _AuFlush - Flush the Au request buffer.  If the buffer is empty, no
319  * action is taken.  This routine correctly handles incremental writes.
320  * This routine may have to be reworked if int < AuInt32.
321  */
322 void
323 _AuFlush (AuServer *aud)
324 {
325 	AuInt32 size, todo;
326 	int write_stat;
327 	char *bufindex;
328 
329 	if (aud->flags & AuServerFlagsIOError) return;
330 
331 	size = todo = aud->bufptr - aud->buffer;
332 	bufindex = aud->bufptr = aud->buffer;
333 	/*
334 	 * While write has not written the entire buffer, keep looping
335 	 * until the entire buffer is written.  bufindex will be incremented
336 	 * and size decremented as buffer is written out.
337 	 */
338 	while (size) {
339 	    errno = 0;
340 	    write_stat = WriteToServer(aud->fd, bufindex, (int) todo);
341 	    if (write_stat >= 0) {
342 		size -= write_stat;
343 		todo = size;
344 		bufindex += write_stat;
345 	    } else if (ETEST(errno)) {
346 		_AuWaitForWritable(aud);
347 #ifdef SUNSYSV
348 	    } else if (errno == 0) {
349 		_AuWaitForWritable(aud);
350 #endif
351 #ifdef EMSGSIZE
352 	    } else if (errno == EMSGSIZE) {
353 		if (todo > 1)
354 		  todo >>= 1;
355 		else
356 		  _AuWaitForWritable(aud);
357 #endif
358 	    } else if (errno != EINTR) {
359 		/* Write failed! */
360 		/* errno set by write system call. */
361 		_AuIOError(aud);
362 	    }
363 	}
364 	aud->last_req = (char *)&_dummy_request;
365 }
366 
367 int
368 _AuEventsQueued (AuServer *aud, int mode)
369 {
370 	int len;
371 	int pend;
372 	_AuAlignedBuffer buf;
373 	auReply *rep;
374 
375 	if (mode == AuEventsQueuedAfterFlush)
376 	{
377 	    _AuFlush(aud);
378 	    if (aud->qlen)
379 		return(aud->qlen);
380 	}
381 	if (aud->flags & AuServerFlagsIOError) return(aud->qlen);
382 	if (BytesReadable(aud->fd, (char *) &pend) < 0)
383 	    _AuIOError(aud);
384 #ifdef AUCONN_CHECK_FREQ
385 	/* This is a crock, required because FIONREAD or equivalent is
386 	 * not guaranteed to detect a broken connection.
387 	 */
388 	if (!pend && !aud->qlen && ++aud->conn_checker >= AUCONN_CHECK_FREQ)
389 	{
390 	    fd_set r_mask;
391 	    static struct timeval zero_time;
392 
393 	    aud->conn_checker = 0;
394 	    FD_ZERO(&r_mask);
395 	    FD_SET(aud->fd, &r_mask);
396 	    if ((pend = select(aud->fd + 1, &r_mask,
397 		(fd_set *)NULL, (fd_set *)NULL,
398 			      &zero_time)) != 0)
399 	    {
400 		if (pend > 0)
401 		{
402 		    if (BytesReadable(aud->fd, (char *) &pend) < 0)
403 			_AuIOError(aud);
404 		    /* we should not get zero, if we do, force a read */
405 		    if (!pend)
406 			pend = SIZEOF(auReply);
407 		}
408 		else if (pend < 0 && errno != EINTR)
409 		    _AuIOError(aud);
410 	    }
411 	}
412 #endif /* AUCONN_CHECK_FREQ */
413 	if (!(len = pend))
414 	    return(aud->qlen);	/* _AuFlush can enqueue events */
415       /* Force a read if there is not enough data.  Otherwise,
416        * a select() loop at a higher-level will spin undesirably,
417        * and we've seen at least one OS that appears to not update
418        * the result from FIONREAD once it has returned nonzero.
419        */
420 	if (len < SIZEOF(auReply))
421 	    len = SIZEOF(auReply);
422 	else if (len > BUFSIZE)
423 	    len = BUFSIZE;
424 	len = (len / SIZEOF(auReply)) * SIZEOF(auReply);
425 #ifdef AUCONN_CHECK_FREQ
426 	aud->conn_checker = 0;
427 #endif
428 	_AuRead (aud, buf.buf, (AuInt32) len);
429 
430 	STARTITERATE(rep,auReply,buf.buf,len > 0) {
431 	    if (rep->generic.type == Au_Reply) {
432 		pend = len;
433 		RESETITERPTR(rep,auReply,
434 			     _AuAsyncReply (aud, rep,
435 					   ITERPTR(rep), &pend, AuTrue));
436 		len = pend;
437 	    } else {
438 		if (rep->generic.type == Au_Error)
439 		    _AuError (aud, (auError *)rep);
440 		else   /* must be an event packet */
441 		    _AuEnq (aud, (auEvent *)rep, AuEventEnqueuedByUnknown);
442 		INCITERPTR(rep,auReply);
443 		len -= SIZEOF(auReply);
444 	    }
445 	} ENDITERATE
446 	return(aud->qlen);
447 }
448 
449 /* _AuReadEvents - Flush the output queue,
450  * then read as many events as possible (but at least 1) and enqueue them
451  */
452 void
453 _AuReadEvents(AuServer *aud)
454 {
455   _AuAlignedBuffer buf;
456   int pend;
457   int len;
458   auReply *rep;
459   AuBool not_yet_flushed = AuTrue;
460 
461   /* lock read access to the server */
462   _AuLockMutex(_rev_mutex);
463 
464   do {
465     /* find out how much data can be read */
466     if (BytesReadable(aud->fd, (char *) &pend) < 0)
467       _AuIOError(aud);
468     len = pend;
469 
470     /* must read at least one auEvent; if none is pending, then
471        we'll just flush and block waiting for it */
472     if (len < SIZEOF(auEvent)) {
473       len = SIZEOF(auEvent);
474       /* don't flush until we block the first time */
475       if (not_yet_flushed) {
476 	int qlen = aud->qlen;
477 	_AuFlush (aud);
478 	if (qlen != aud->qlen) return;
479 	not_yet_flushed = AuFalse;
480       }
481     }
482 
483     /* but we won't read more than the max buffer size */
484     if (len > BUFSIZE)
485       len = BUFSIZE;
486 
487     /* round down to an integral number of AuReps */
488     len = (len / SIZEOF(auEvent)) * SIZEOF(auEvent);
489 
490     _AuRead (aud, buf.buf, (AuInt32) len);
491 
492     STARTITERATE(rep,auReply,buf.buf,len > 0) {
493       if (rep->generic.type == Au_Reply) {
494 	pend = len;
495 	RESETITERPTR(rep,auReply,
496 		     _AuAsyncReply (aud, rep,
497 				    ITERPTR(rep), &pend, AuTrue));
498 	len = pend;
499       } else {
500 	if (rep->generic.type == Au_Error)
501 	  _AuError (aud, (auError *) rep);
502 	else   /* must be an event packet */
503 	  _AuEnq (aud, (auEvent *)rep, AuEventEnqueuedByUnknown);
504 	INCITERPTR(rep,auReply);
505 	len -= SIZEOF(auReply);
506       }
507     } ENDITERATE
508   } while (aud->head == NULL);
509 
510   _AuUnlockMutex(_rev_mutex);
511 
512 }
513 
514 /*
515  * _AuRead - Read bytes from the socket taking into account incomplete
516  * reads.  This routine may have to be reworked if int < AuInt32.
517  */
518 void
519 _AuRead (AuServer *aud, char *data, AuInt32 size)
520 {
521 	AuInt32 bytes_read;
522 
523 	if ((aud->flags & AuServerFlagsIOError) || size == 0) return;
524 	errno = 0;
525 
526 	while ((bytes_read = ReadFromServer(aud->fd, data, (int)size))
527 	       != size)
528 	  {
529 
530 	    if (bytes_read > 0) {
531 	      size -= bytes_read;
532 	      data += bytes_read;
533 	    }
534 	    else if (ETEST(errno)) {
535 	      _AuWaitForReadable(aud);
536 	      errno = 0;
537 	    }
538 #ifdef SUNSYSV
539 	    else if (errno == 0) {
540 	      _AuWaitForReadable(aud);
541 	    }
542 #endif
543 	    else if (bytes_read == 0) {
544 	      /* Read failed because of end of file! */
545 	      errno = EPIPE;
546 	      _AuIOError(aud);
547 	    }
548 
549 	    else  /* bytes_read is less than 0; presumably -1 */ {
550 	      /* If it's a system call interrupt, it's not an error. */
551 	      if (errno != EINTR)
552 		_AuIOError(aud);
553 	    }
554 
555 	  }
556 }
557 
558 #ifdef WORD64
559 
560 /*
561  * XXX This is a *really* stupid way of doing this....
562  * PACKBUFFERSIZE must be a multiple of 4.
563  */
564 
565 #define PACKBUFFERSIZE 4096
566 
567 
568 /*
569  * _AuRead32 - Read bytes from the socket unpacking each 32 bits
570  *            into a AuInt32 (64 bits on a CRAY computer).
571  *
572  */
573 static _doXRead32 (AuServer *aud, AuInt32 *data,
574                    AuInt32 size, char *packbuffer)
575 {
576  AuInt32 *lpack,*lp;
577  AuInt32 mask32 = 0x00000000ffffffff;
578  AuInt32 maskw, nwords, i, bits;
579 
580         _AuReadPad (aud, packbuffer, size);
581 
582         lp = data;
583         lpack = (AuInt32 *) packbuffer;
584         nwords = size >> 2;
585         bits = 32;
586 
587         for(i=0;i<nwords;i++){
588             maskw = mask32 << bits;
589            *lp++ = ( *lpack & maskw ) >> bits;
590             bits = bits ^32;
591             if(bits){
592                lpack++;
593             }
594         }
595 }
596 
597 _AuRead32 (AuServer *aud, AuInt32 *data, AuInt32 len)
598 {
599     char packbuffer[PACKBUFFERSIZE];
600     unsigned nunits = PACKBUFFERSIZE >> 2;
601 
602     for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
603 	_doXRead32 (aud, data, PACKBUFFERSIZE, packbuffer);
604     }
605     if (len) _doXRead32 (aud, data, len, packbuffer);
606 }
607 
608 
609 
610 /*
611  * _AuRead16 - Read bytes from the socket unpacking each 16 bits
612  *            into a AuInt32 (64 bits on a CRAY computer).
613  *
614  */
615 static _doXRead16 (AuServer *aud, short *data,
616                    AuInt32 size, char *packbuffer)
617         AuServer *aud;
618         short *data;
619         AuInt32 size;
620 	char *packbuffer;
621 {
622 	AuInt32 *lpack,*lp;
623 	AuInt32 mask16 = 0x000000000000ffff;
624 	AuInt32 maskw, nwords, i, bits;
625 
626         _AuRead(aud,packbuffer,size);	/* don't do a padded read... */
627 
628         lp = (AuInt32 *) data;
629         lpack = (AuInt32 *) packbuffer;
630         nwords = size >> 1;  /* number of 16 bit words to be unpacked */
631         bits = 48;
632         for(i=0;i<nwords;i++){
633             maskw = mask16 << bits;
634            *lp++ = ( *lpack & maskw ) >> bits;
635             bits -= 16;
636             if(bits < 0){
637                lpack++;
638                bits = 48;
639             }
640         }
641 }
642 
643 _AuRead16 (AuServer *aud, short *data, AuInt32 len)
644 {
645     char packbuffer[PACKBUFFERSIZE];
646     unsigned nunits = PACKBUFFERSIZE >> 1;
647 
648     for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
649 	_doXRead16 (aud, data, PACKBUFFERSIZE, packbuffer);
650     }
651     if (len) _doXRead16 (aud, data, len, packbuffer);
652 }
653 
654 _AuRead16Pad (AuServer *aud, short *data, AuInt32 size)
655 {
656     int slop = (size & 3);
657     short slopbuf[3];
658 
659     _AuRead16 (aud, data, size);
660     if (slop > 0) {
661 	_AuRead16 (aud, slopbuf, 4 - slop);
662     }
663 }
664 #endif /* WORD64 */
665 
666 
667 /*
668  * _AuReadPad - Read bytes from the socket taking into account incomplete
669  * reads.  If the number of bytes is not 0 mod 4, read additional pad
670  * bytes. This routine may have to be reworked if int < AuInt32.
671  */
672 void
673 _AuReadPad (AuServer *aud, char *data, AuInt32 size)
674 {
675     	AuInt32 bytes_read;
676 	struct iovec iov[2];
677 	char pad[3];
678 	char *p;
679 
680 	if ((aud->flags & AuServerFlagsIOError) || size == 0) return;
681 	iov[0].iov_len = (int)size;
682 	iov[0].iov_base = data;
683 	/*
684 	 * The following hack is used to provide 32 bit AuInt32-word
685 	 * aligned padding.  The [1] vector is of length 0, 1, 2, or 3,
686 	 * whatever is needed.
687 	 */
688 
689 	iov[1].iov_len = padlength[size & 3];
690 	iov[1].iov_base = pad;
691 	size += iov[1].iov_len;
692 	errno = 0;
693 				/* JET - we'll use a little indirect ptr */
694 				/* arithmetic to get around the */
695 				/* fact that iov_base is often a void * */
696 
697 	while ((bytes_read = ReadvFromServer (aud->fd, iov, 2)) != size)
698 	  {
699 
700 	    if (bytes_read > 0)
701 	      {
702 		size -= bytes_read;
703 	    	if ((iov[0].iov_len -= bytes_read) < 0)
704 		  {
705 		    iov[1].iov_len += iov[0].iov_len;
706 
707 		    p = (char *)iov[1].iov_base;
708 		    p -= iov[0].iov_len;
709 		    iov[1].iov_base = p;
710 
711 		    iov[0].iov_len = 0;
712 		  }
713 	    	else
714 		  {
715 		    p = (char *)iov[0].iov_base;
716 		    p += bytes_read;
717 		    iov[0].iov_base = p;
718 		  }
719 	      }
720 	    else if (ETEST(errno))
721 	      {
722 		_AuWaitForReadable(aud);
723 		errno = 0;
724 	      }
725 #ifdef SUNSYSV
726 	    else if (errno == 0)
727 	      {
728 		_AuWaitForReadable(aud);
729 	      }
730 #endif
731 	    else if (bytes_read == 0)
732 	      {
733 		/* Read failed because of end of file! */
734 		errno = EPIPE;
735 		_AuIOError(aud);
736 	      }
737 	    else  /* bytes_read is less than 0; presumably -1 */
738 	      {
739 		/* If it's a system call interrupt, it's not an error. */
740 		if (errno != EINTR)
741 		  _AuIOError(aud);
742 	      }
743 	  }
744 }
745 
746 /*
747  * _AuSend - Flush the buffer and send the client data. 32 bit word aligned
748  * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
749  * This routine may have to be reworked if int < AuInt32;
750  */
751 void
752 _AuSend (AuServer *aud, char *data, AuInt32 size)
753 {
754 	struct iovec iov[3];
755 	static char pad[3] = {0, 0, 0};
756            /* XText8 and XText16 require that the padding bytes be zero! */
757 
758 	AuInt32 skip = 0;
759 	AuInt32 audbufsize = (aud->bufptr - aud->buffer);
760 	AuInt32 padsize = padlength[size & 3];
761 	AuInt32 total = audbufsize + size + padsize;
762 	AuInt32 todo = total;
763 
764 	if (aud->flags & AuServerFlagsIOError) return;
765 
766 	/*
767 	 * There are 3 pieces that may need to be written out:
768 	 *
769 	 *     o  whatever is in the server buffer
770 	 *     o  the data passed in by the user
771 	 *     o  any padding needed to 32bit align the whole mess
772 	 *
773 	 * This loop looks at all 3 pieces each time through.  It uses skip
774 	 * to figure out whether or not a given piece is needed.
775 	 */
776 	while (total) {
777 	    AuInt32 before = skip;		/* amount of whole thing written */
778 	    AuInt32 remain = todo;		/* amount to try this time, <= total */
779 	    int i = 0;
780 	    AuInt32 len;
781 
782 	    /* You could be very general here and have "in" and "out" iovecs
783 	     * and write a loop without using a macro, but what the heck.  This
784 	     * translates to:
785 	     *
786 	     *     how much of this piece is new?
787 	     *     if more new then we are trying this time, clamp
788 	     *     if nothing new
789 	     *         then bump down amount already written, for next piece
790 	     *         else put new stuff in iovec, will need all of next piece
791 	     *
792 	     * Note that todo had better be at least 1 or else we'll end up
793 	     * writing 0 iovecs.
794 	     */
795 #define InsertIOV(pointer, length) \
796 	    len = (length) - before; \
797 	    if (len > remain) \
798 		len = remain; \
799 	    if (len <= 0) { \
800 		before = (-len); \
801 	    } else { \
802 		iov[i].iov_len = len; \
803 		iov[i].iov_base = (pointer) + before; \
804 		i++; \
805 		remain -= len; \
806 		before = 0; \
807 	    }
808 
809 	    InsertIOV (aud->buffer, audbufsize)
810 	    InsertIOV (data, size)
811 	    InsertIOV (pad, padsize)
812 
813 	    errno = 0;
814 	    if ((len = WritevToServer(aud->fd, iov, i)) >= 0) {
815 		skip += len;
816 		total -= len;
817 		todo = total;
818 	    } else if (ETEST(errno)) {
819 		_AuWaitForWritable(aud);
820 #ifdef SUNSYSV
821 	    } else if (errno == 0) {
822 		_AuWaitForWritable(aud);
823 #endif
824 #ifdef EMSGSIZE
825 	    } else if (errno == EMSGSIZE) {
826 		if (todo > 1)
827 		  todo >>= 1;
828 		else
829 		  _AuWaitForWritable(aud);
830 #endif
831 	    } else if (errno != EINTR) {
832 		_AuIOError(aud);
833 	    }
834 	}
835 
836 	aud->bufptr = aud->buffer;
837 	aud->last_req = (char *) & _dummy_request;
838 }
839 
840 /*
841  * _AuAllocID - normal resource ID allocation routine.  A client
842  * can roll his own and instatantiate it if he wants, but must
843  * follow the rules.
844  */
845 AuID _AuAllocID (AuServer *aud)
846 {
847    AuID id;
848 
849    id = aud->resource_id << aud->resource_shift;
850    if (id <= aud->resource_mask) {
851        aud->resource_id++;
852        return (aud->resource_base + id);
853    }
854    if (id != 0x10000000) {
855        (void) fprintf(stderr,
856 		      "audiolib: resource ID allocation space exhausted!\n");
857        id = 0x10000000;
858        aud->resource_id = id >> aud->resource_shift;
859    }
860    return id;
861 }
862 
863 /*
864  * The hard part about this is that we only get 16 bits from a reply.  Well,
865  * then, we have three values that will march aAuInt32, with the following
866  * invariant:
867  *	aud->last_request_read <= rep->sequenceNumber <= aud->request
868  * The right choice for rep->sequenceNumber is the largest that
869  * still meets these constraints.
870  */
871 
872 AuUint32
873 _AuSetLastRequestRead(AuServer *aud, auGenericReply *rep)
874 {
875     AuUint32	newseq, lastseq;
876 
877     newseq = (aud->last_request_read & ~((AuUint32)0xffff)) |
878 	     rep->sequenceNumber;
879     lastseq = aud->last_request_read;
880     while (newseq < lastseq) {
881 	newseq += 0x10000;
882 	if (newseq > aud->request) {
883 	    (void) fprintf (stderr,
884 	    "audiolib: sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
885 			    newseq, aud->request,
886 			    (unsigned int) rep->type);
887 	    newseq -= 0x10000;
888 	    break;
889 	}
890     }
891 
892     aud->last_request_read = newseq;
893     return(newseq);
894 }
895 
896 /*
897  * _AuReply - Wait for a reply packet and copy its contents into the
898  * specified rep.  Mean while we must handle error and event packets that
899  * we may encounter.
900  *
901  *   int extra;		number of 32-bit words expected after the reply
902  *   AuBool discard;	should I discard data following "extra" words?
903  */
904 AuBool _AuReply (AuServer *aud, auReply *rep,
905                  int extra, AuBool discard, AuStatus *ret_status)
906 {
907     /* Pull out the serial number now, so that (currently illegal) requests
908      * generated by an error handler don't confuse us.
909      */
910     AuUint32 cur_request = aud->request;
911     AuStatus tmpstatus;
912 
913     if (!ret_status)
914 	ret_status = &tmpstatus;
915 
916     *ret_status = AuSuccess;
917 
918     if (aud->flags & AuServerFlagsIOError) {
919 	*ret_status = AuBadConnection;
920 	return AuFalse;
921     }
922 
923     _AuFlush(aud);
924     while (1) {
925 	_AuRead(aud, (char *)rep, (AuInt32)SIZEOF(auReply));
926 	switch ((int)rep->generic.type) {
927 
928 	    case Au_Reply:
929 	        /* Reply received.  Fast update for synchronous replies,
930 		 * but deal with multiple outstanding replies.
931 		 */
932 	        if (rep->generic.sequenceNumber == (cur_request & 0xffff))
933 		    aud->last_request_read = cur_request;
934 		else {
935 		    int pend = SIZEOF(auReply);
936 		    if (_AuAsyncReply(aud, rep, (char *)rep, &pend, AuFalse)
937 			!= (char *)rep)
938 			continue;
939 		}
940 		if (extra == 0) {
941 		    if (discard && (rep->generic.length > 0))
942 		       /* unexpectedly AuInt32 reply! */
943 		       _AuEatData (aud, rep->generic.length << 2);
944 		    return AuTrue;
945 		    }
946 		if (extra == rep->generic.length) {
947 		    /*
948 		     * Read the extra data into storage immediately following
949 		     * the GenericReply structure.
950 		     */
951 		    _AuRead (aud, (char *) (NEXTPTR(rep,auReply)),
952 			    ((AuInt32)extra) << 2);
953 		    return AuTrue;
954 		    }
955 		if (extra < rep->generic.length) {
956 		    /* Actual reply is AuInt32er than "extra" */
957 		    _AuRead (aud, (char *) (NEXTPTR(rep,auReply)),
958 			    ((AuInt32)extra) << 2);
959 		    if (discard)
960 		        _AuEatData (aud, (rep->generic.length - extra) << 2);
961 		    return AuTrue;
962 		    }
963 		/*
964 		 *if we get here, then extra > rep->generic.length--meaning we
965 		 * read a reply that's shorter than we expected.  This is an
966 		 * error,  but we still need to figure out how to handle it...
967 		 */
968 		_AuRead (aud, (char *) (NEXTPTR(rep,auReply)),
969 			((AuInt32) rep->generic.length) << 2);
970 		_AuIOError (aud);
971 		*ret_status = AuBadConnection;
972 		return AuFalse;
973 
974     	    case Au_Error:
975 	    	{
976 	        _AuExtension *ext;
977 		AuBool ret = AuFalse;
978 		AuBool ret_code = AuFalse;
979 		auError *err = (auError *) rep;
980 		AuUint32 serial;
981 
982 		*ret_status = (int) err->errorCode;
983 		serial = _AuSetLastRequestRead(aud, (auGenericReply *)rep);
984 		if (serial == cur_request) {
985 		    /*
986 		     * Don't die if the caller asked for a ret_status
987 		     */
988 		    if (ret_status != &tmpstatus)
989 			return AuFalse;
990 
991 #ifdef checkforanyreqsthatexpectreplies
992 		    /* do not die on "no such font", "can't allocate",
993 		       "can't grab" failures */
994 		    switch ((int)err->errorCode) {
995 		      case AuBadName:
996 		      case AuBadAlloc:
997 		      case AuBadAccess:
998 			return AuFalse;
999 		    }
1000 #endif
1001 		}
1002 		/*
1003 		 * we better see if there is an extension who may
1004 		 * want to suppress the error.
1005 		 */
1006 		for (ext = aud->ext_procs; !ret && ext; ext = ext->next) {
1007 		    if (ext->error)
1008 		       ret = (*ext->error)(aud, err, &ext->codes, &ret_code);
1009 		}
1010 		if (!ret) {
1011 		    _AuError(aud, err);
1012 		    ret_code = AuFalse;
1013 		}
1014 		if (serial == cur_request)
1015 		    return ret_code;
1016 		}
1017 		break;
1018 	    default:
1019 		_AuEnq(aud, (auEvent *) rep, AuEventEnqueuedByReply);
1020 		break;
1021 	    }
1022 	}
1023 }
1024 
1025 static char *
1026 _AuAsyncReply(AuServer *aud, auReply *rep, char *buf,
1027               int *lenp, AuBool discard)
1028 {
1029     _AuAsyncHandler *async, *next;
1030     int len;
1031     AuBool consumed = AuFalse;
1032     char *nbuf;
1033 
1034     (void) _AuSetLastRequestRead(aud, &rep->generic);
1035     len = SIZEOF(auReply) + (rep->generic.length << 2);
1036 
1037     for (async = aud->async_handlers; async; async = next) {
1038 	next = async->next;
1039 	if ((consumed = (*async->handler)(aud, rep, buf, *lenp, async->data)) != 0)
1040 	    break;
1041     }
1042     if (!consumed) {
1043 	if (!discard)
1044 	    return buf;
1045 	(void) fprintf(stderr,
1046 		       "audiolib: unexpected async reply (sequence 0x%lx)!\n",
1047 		       aud->last_request_read);
1048 	if (len > *lenp)
1049 	    _AuEatData(aud, len - *lenp);
1050     }
1051     if (len >= *lenp) {
1052 	buf += *lenp;
1053 	*lenp = 0;
1054 	return buf;
1055     }
1056     *lenp -= len;
1057     buf += len;
1058     len = *lenp;
1059     nbuf = buf;
1060     while (len > SIZEOF(auReply)) {
1061 	if (*buf == Au_Reply)
1062 	    return nbuf;
1063 	buf += SIZEOF(auReply);
1064 	len -= SIZEOF(auReply);
1065     }
1066     if (len > 0 && len < SIZEOF(auReply)) {
1067 	buf = nbuf;
1068 	len = SIZEOF(auReply) - len;
1069 	nbuf -= len;
1070 	bcopy(buf, nbuf, *lenp);
1071 	_AuRead(aud, nbuf + *lenp, (AuInt32)len);
1072 	*lenp += len;
1073     }
1074     return nbuf;
1075 }
1076 
1077 /*
1078  * _AuForceRoundTrip - send the request that has just been queued and watch
1079  * for any errors that it might generate.  Callers should set
1080  * error_code, major, and minor all to 0 to catch all errors.
1081  */
1082 AuBool
1083 _AuForceRoundTrip (AuServer *aud, int error_code, int majorop, int minorop,
1084                    AuStatus *ret_status)
1085 {
1086     AuUint32 seq = aud->request;	 /* get previous request */
1087     auGetCloseDownModeReply rep;
1088     auReq *req;
1089     _AuAsyncHandler async;
1090     _AuAsyncErrorState async_state;
1091 
1092     async_state.min_sequence_number = seq;
1093     async_state.max_sequence_number = seq;
1094     async_state.error_code = error_code;
1095     async_state.major_opcode = majorop;
1096     async_state.minor_opcode = minorop;
1097     async_state.error_count = 0;
1098 
1099     _AuEnqAsyncHandler (aud, &async, _AuAsyncErrorHandler, &async_state);
1100 
1101     _AuGetEmptyReq(GetCloseDownMode, req, aud);    /* AuSync() */
1102     (void) _AuReply (aud, (auReply *)&rep, 0, auTrue, (AuStatus *) NULL);
1103 
1104     _AuDeqAsyncHandler(aud, &async);
1105 
1106     if (ret_status) {
1107 	if (async_state.error_count > 0)
1108 	    *ret_status = async_state.last_error_received;
1109 	else
1110 	    *ret_status = AuSuccess;
1111     }
1112     return (async_state.error_count == 0 ? AuTrue : AuFalse);
1113 }
1114 
1115 
1116 
1117 
1118 /* Read and discard "n" 8-bit bytes of data */
1119 
1120 void _AuEatData (AuServer *aud, AuUint32 n)
1121 {
1122 #define SCRATCHSIZE 2048
1123     char buf[SCRATCHSIZE];
1124 
1125     while (n > 0) {
1126 	AuInt32 bytes_read = (n > SCRATCHSIZE) ? SCRATCHSIZE : n;
1127 	_AuRead (aud, buf, bytes_read);
1128 	n -= bytes_read;
1129     }
1130 #undef SCRATCHSIZE
1131 }
1132 
1133 AuEventEnqHandlerRec *
1134 AuRegisterEventEnqHandler(AuServer *aud, int who,
1135                           AuEventEnqHandlerCallback callback,
1136                           AuPointer data)
1137 {
1138     AuEventEnqHandlerRec *handler;
1139 
1140     if (!(handler =
1141 	  (AuEventEnqHandlerRec *) Aumalloc(sizeof(AuEventEnqHandlerRec))))
1142 	return NULL;
1143 
1144     handler->who = who;
1145     handler->callback = callback;
1146     handler->data = data;
1147 
1148     _AuAddToLinkedList(aud->eventenqhandlerq, handler);
1149 
1150     return handler;
1151 }
1152 
1153 void
1154 AuUnregisterEventEnqHandler(AuServer *aud, AuEventEnqHandlerRec *handler)
1155 {
1156     _AuRemoveFromLinkedList(aud->eventenqhandlerq, handler);
1157     Aufree(handler);
1158 }
1159 
1160 static void
1161 _AuEventEnqueued(AuServer *aud, int who, AuEvent *event)
1162 {
1163     AuEventEnqHandlerRec *p = aud->eventenqhandlerq,
1164                    *next;
1165 
1166     while (p)
1167     {
1168 	next = p->next;
1169 	if (p->who == AuEventEnqueuedByAny || p->who == who)
1170 	    (*p->callback) (aud, p, event, p->data);
1171 	p = next;
1172     }
1173 }
1174 
1175 /*
1176  * _AuEnq - Place event packets on the server's queue.
1177  */
1178 static void
1179 _AuEnq (AuServer *aud, auEvent *event, int who)
1180 {
1181 	_AuQEvent *qelt;
1182 
1183 /*NOSTRICT*/
1184 	if ((qelt = aud->qfree) != 0) {
1185 		/* If aud->qfree is non-NULL do this, else malloc a new one. */
1186 		aud->qfree = qelt->next;
1187 	}
1188 	else if ((qelt =
1189 	    (_AuQEvent *) Aumalloc((unsigned)sizeof(_AuQEvent))) == NULL) {
1190 		/* Malloc call failed! */
1191 		errno = ENOMEM;
1192 		_AuIOError(aud);
1193 	}
1194 	qelt->next = NULL;
1195 	/* go call through server to find proper event reformatter */
1196 	if ((*aud->event_vec[event->u.u.type & 0177])(aud, &qelt->event, event)) {
1197 	    if (aud->tail)	aud->tail->next = qelt;
1198 	    else 		aud->head = qelt;
1199 
1200 	    aud->tail = qelt;
1201 	    aud->qlen++;
1202 	    _AuEventEnqueued(aud, who, &qelt->event);
1203 	} else {
1204 	    /* ignored, or stashed away for many-to-one compression */
1205 	    qelt->next = aud->qfree;
1206 	    aud->qfree = qelt;
1207 	}
1208 }
1209 /*
1210  * EventToWire in separate file in that often not needed.
1211  *
1212  * AuServer *aud;	 pointer to server structure
1213  * AuEvent *re;	         pointer to where event should be reformatted
1214  * auEvent *event;	 wire protocol event
1215  */
1216 
1217 /*ARGSUSED*/
1218 AuBool
1219 _AuUnknownWireEvent(AuServer *aud, AuEvent *re,
1220                     auEvent *event)
1221 {
1222 #ifdef notdef
1223 	(void) fprintf(stderr,
1224 	    "audiolib: unhandled wire event! event number = %d, server = %x\n.",
1225 			event->u.u.type, aud);
1226 #endif
1227 	return(AuFalse);
1228 }
1229 
1230 /*ARGSUSED*/
1231 AuStatus
1232 _AuUnknownNativeEvent(AuServer *aud, AuEvent *re,
1233                       auEvent *event)
1234 {
1235 #ifdef notdef
1236 	(void) fprintf(stderr,
1237  	   "audiolib: unhandled native event! event number = %d, server = %x\n.",
1238 			re->type, aud);
1239 #endif
1240 	return(0);
1241 }
1242 /*
1243  * reformat a wire event into an AuEvent structure of the right type.
1244  */
1245 AuBool
1246 _AuWireToEvent(AuServer *aud, AuEvent *re,
1247                auEvent *event)
1248 {
1249 
1250     re->type = event->u.u.type & 0x7f;
1251     ((AuAnyEvent *) re)->serial = _AuSetLastRequestRead(aud,
1252 						  (auGenericReply *) event);
1253     ((AuAnyEvent *) re)->send_event = ((event->u.u.type & 0x80) != 0);
1254     ((AuAnyEvent *) re)->server = aud;
1255     ((AuAnyEvent *) re)->time = event->u.u.time;
1256 
1257     /*
1258      * Ignore the leading bit of the event type since it is set when a client
1259      * sends an event rather than the server.
1260      */
1261 
1262     switch (event->u.u.type & 0177)
1263     {
1264 	case AuEventTypeElementNotify:
1265 	    {
1266 		AuElementNotifyEvent *ev =
1267 		(AuElementNotifyEvent *) re;
1268 #undef xfer
1269 #define xfer(x) ev->x = event->u.elementNotify.x
1270 		xfer(flow);
1271 		xfer(element_num);
1272 		xfer(kind);
1273 		xfer(prev_state);
1274 		xfer(cur_state);
1275 		xfer(reason);
1276 		xfer(num_bytes);
1277 	    }
1278 	    break;
1279 	case AuEventTypeMonitorNotify:
1280 	    {
1281 		AuMonitorNotifyEvent *ev =
1282 		(AuMonitorNotifyEvent *) re;
1283 #undef xfer
1284 #define xfer(x) ev->x = event->u.monitorNotify.x
1285 		xfer(flow);
1286 		xfer(element_num);
1287 		xfer(format);
1288 		xfer(num_tracks);
1289 		xfer(count);
1290 		xfer(num_fields);
1291 		xfer(data);
1292 		xfer(data1);
1293 		xfer(data2);
1294 	    }
1295 	    break;
1296 	default:
1297 	    return (_AuUnknownWireEvent(aud, re, event));
1298     }
1299     return (AuTrue);
1300 }
1301 
1302 
1303 #ifndef USL_SHARELIB
1304 
1305 static char *_SysErrorMsg (int n)
1306 {
1307   return (strerror(n));
1308 }
1309 
1310 #endif 	/* USL sharedlibs in don't define for AUD3.2 */
1311 
1312 
1313 /*
1314  * _AuDefaultIOError - Default fatal system error reporting routine.  Called
1315  * when an Au internal system error is encountered.
1316  */
1317 void
1318 _AuDefaultIOError (AuServer *aud)
1319 {
1320 	if (errno == EPIPE) {
1321 	    (void) fprintf (stderr,
1322 	"NAS connection to %s broken (explicit kill or server shutdown).\r\n",
1323 			    AuServerString (aud));
1324 	} else {
1325 	    (void) fprintf (stderr,
1326 			"AuIO:  fatal IO error %d (%s) on audio server \"%s\"\r\n",
1327 			errno, _SysErrorMsg (errno), AuServerString (aud));
1328 	    (void) fprintf (stderr,
1329 	 "      after %lu requests (%lu known processed) with %d events remaining.\r\n",
1330 			AuServerNextRequest(aud) - 1, AuServerLastKnownRequestProcessed(aud),
1331 			AuServerQLength(aud));
1332 
1333 	}
1334 	exit(1);                /* JET - is there a way to handle this
1335                                    w/o being so heavy-handed? */
1336 }
1337 
1338 
1339 int _AuPrintDefaultError (AuServer *aud, AuErrorEvent *event, FILE *fp)
1340 {
1341     char buffer[BUFSIZ];
1342     char mesg[BUFSIZ];
1343     char number[32];
1344     const char *mtype = "audiolib";
1345     _AuExtension *ext = (_AuExtension *)NULL;
1346     _AuExtension *bext = (_AuExtension *)NULL;
1347     AuGetErrorText(aud, event->error_code, buffer, BUFSIZ);
1348     AuGetErrorDatabaseText(aud, mtype, "AuError", "Audio Error", mesg, BUFSIZ);
1349     (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
1350     AuGetErrorDatabaseText(aud, mtype, "MajorCode", "Request Major code %d",
1351 	mesg, BUFSIZ);
1352     (void) fprintf(fp, mesg, event->request_code);
1353     if (event->request_code < 128) {
1354 	sprintf(number, "%d", event->request_code);
1355 	AuGetErrorDatabaseText(aud, "AuRequest", number, "", buffer, BUFSIZ);
1356     } else {
1357 	for (ext = aud->ext_procs;
1358 	     ext && (ext->codes.major_opcode != event->request_code);
1359 	     ext = ext->next)
1360 	    /* SUPPRESS 530 */
1361 	  ;
1362 	if (ext)
1363 	    strcpy(buffer, ext->name);
1364 	else
1365 	    buffer[0] = '\0';
1366     }
1367     (void) fprintf(fp, " (%s)\n", buffer);
1368     if (event->request_code >= 128) {
1369 	AuGetErrorDatabaseText(aud, mtype, "MinorCode", "Request Minor code %d",
1370 			      mesg, BUFSIZ);
1371 	fputs("  ", fp);
1372 	(void) fprintf(fp, mesg, event->minor_code);
1373 	if (ext) {
1374 	    sprintf(mesg, "%s.%d", ext->name, event->minor_code);
1375 	    AuGetErrorDatabaseText(aud, "AuRequest", mesg, "", buffer, BUFSIZ);
1376 	    (void) fprintf(fp, " (%s)", buffer);
1377 	}
1378 	fputs("\n", fp);
1379     }
1380     if (event->error_code >= 128) {
1381 	/* kludge, try to find the extension that caused it */
1382 	buffer[0] = '\0';
1383 	for (ext = aud->ext_procs; ext; ext = ext->next) {
1384 	    if (ext->error_string)
1385 		(*ext->error_string)(aud, event->error_code, &ext->codes,
1386 				     buffer, BUFSIZ);
1387 	    if (buffer[0]) {
1388 		bext = ext;
1389 		break;
1390 	    }
1391 	    if (ext->codes.first_error &&
1392 		ext->codes.first_error < (int) event->error_code &&
1393 		(!bext || ext->codes.first_error > bext->codes.first_error))
1394 		bext = ext;
1395 	}
1396 	if (bext)
1397 	    sprintf(buffer, "%s.%d", bext->name,
1398 		    event->error_code - bext->codes.first_error);
1399 	else
1400 	    strcpy(buffer, "Value");
1401 	AuGetErrorDatabaseText(aud, mtype, buffer, "", mesg, BUFSIZ);
1402 	if (mesg[0]) {
1403 	    fputs("  ", fp);
1404 	    (void) fprintf(fp, mesg, event->resourceid);
1405 	    fputs("\n", fp);
1406 	}
1407 	/* let extensions try to print the values */
1408 	for (ext = aud->ext_procs; ext; ext = ext->next) {
1409 	    if (ext->error_values)
1410 		(*ext->error_values)(aud, event, fp);
1411 	}
1412     }
1413     AuGetErrorDatabaseText(aud, mtype, "ErrorSerial", "Error Serial #%d",
1414 			  mesg, BUFSIZ);
1415     fputs("  ", fp);
1416     (void) fprintf(fp, mesg, event->serial);
1417     AuGetErrorDatabaseText(aud, mtype, "CurrentSerial", "Current Serial #%d",
1418 			  mesg, BUFSIZ);
1419     fputs("\n  ", fp);
1420     (void) fprintf(fp, mesg, aud->request);
1421     fputs("\n", fp);
1422     if (event->error_code == AuBadImplementation) return 0;
1423     return 1;
1424 }
1425 
1426 int _AuDefaultError(AuServer *aud, AuErrorEvent *event)
1427 {
1428     if (_AuPrintDefaultError (aud, event, stderr) == 0) return 0;
1429     exit(1);
1430     /*NOTREACHED*/
1431 }
1432 
1433 /*ARGSUSED*/
1434 AuBool _AuDefaultWireError(AuServer *server, AuErrorEvent *he,
1435                            auError *we)
1436 {
1437     return AuTrue;
1438 }
1439 
1440 /*
1441  * _AuError - upcall internal or user protocol error handler
1442  */
1443 int _AuError (AuServer *aud, auError *rep)
1444 {
1445     /*
1446      * Au_Error packet encountered!  We need to unpack the error before
1447      * giving it to the user.
1448      */
1449     AuEvent event; /* make it a large event */
1450     _AuAsyncHandler *async, *next;
1451 
1452     event.auerror.serial = _AuSetLastRequestRead(aud, (auGenericReply *)rep);
1453 
1454     for (async = aud->async_handlers; async; async = next) {
1455 	next = async->next;
1456 	if ((*async->handler)(aud, (auReply *)rep,
1457 			      (char *)rep, SIZEOF(auError), async->data))
1458 	    return 0;
1459     }
1460 
1461     event.auerror.server = aud;
1462     event.auerror.type = Au_Error;
1463     event.auerror.time = rep->time;
1464     event.auerror.resourceid = rep->resourceID;
1465     event.auerror.error_code = rep->errorCode;
1466     event.auerror.request_code = rep->majorCode;
1467     event.auerror.minor_code = rep->minorCode;
1468     switch (event.auerror.error_code) {
1469       default:
1470 	event.auerror.data.l[0] = rep->data0;
1471 	event.auerror.data.l[1] = rep->data1;
1472 	event.auerror.data.l[2] = rep->data2;
1473 	event.auerror.data.l[3] = rep->data3;
1474     }
1475 
1476     if (aud->error_vec &&
1477 	!(*aud->error_vec[rep->errorCode])(aud, &event.auerror, rep))
1478 	return 0;
1479     if (aud->funcs.error_handler != NULL) {
1480       	return ((*aud->funcs.error_handler)(aud, (AuErrorEvent *) &event));	/* upcall */
1481     } else {
1482 	return _AuDefaultError(aud, (AuErrorEvent *) &event);
1483     }
1484 }
1485 
1486 /*
1487  * _AuIOError - call user connection error handler and exit
1488  */
1489 int _AuIOError (AuServer *aud)
1490 {
1491     aud->flags |= AuServerFlagsIOError;
1492     if (aud->funcs.ioerror_handler != NULL)
1493 	(*aud->funcs.ioerror_handler)(aud);
1494     else
1495 	_AuDefaultIOError(aud);
1496     exit (1);
1497 }
1498 
1499 
1500 /*
1501  * This routine can be used to (cheaply) get some memory within a single
1502  * audiolib routine for scratch space.  It is reallocated from the same place
1503  * each time, unless the library needs a large scratch space.
1504  */
1505 char *_AuAllocScratch (AuServer *aud, AuUint32 nbytes)
1506 {
1507 	if (nbytes > aud->scratch_length) {
1508 	    if (aud->scratch_buffer) Aufree ((void *)aud->scratch_buffer);
1509 	    if ((aud->scratch_buffer =
1510                  (char *)Aumalloc((unsigned) nbytes)) != NULL)
1511               aud->scratch_length = nbytes;
1512 	    else aud->scratch_length = 0;
1513 	}
1514 	return ((char *)aud->scratch_buffer);
1515 }
1516 
1517 
1518 void
1519 AuFree (AuPointer data)
1520 {
1521 	Aufree (data);
1522 }
1523 
1524 #ifdef _AUNEEDBCOPYFUNC
1525 void _Aubcopy(char *b1, char *b2, int length)
1526 {
1527     if (b1 < b2) {
1528 	b2 += length;
1529 	b1 += length;
1530 	while (length--)
1531 	    *--b2 = *--b1;
1532     } else {
1533 	while (length--)
1534 	    *b2++ = *b1++;
1535     }
1536 }
1537 #endif
1538 
1539 #ifdef _AuDataRoutineIsProcedure
1540 void _AuData (AuServer *aud, char *data, AuInt32 len)
1541 {
1542 	if (aud->bufptr + (len) <= aud->bufmax) {
1543 		bcopy(data, aud->bufptr, (int)len);
1544 		aud->bufptr += ((len) + 3) & ~3;
1545 	} else {
1546 		_AuSend(aud, data, len);
1547 	}
1548 }
1549 #endif /* _AuDataRoutineIsProcedure */
1550 
1551 
1552 #ifdef WORD64
1553 
1554 /*
1555  * XXX This is a *really* stupid way of doing this.  It should just use
1556  * aud->bufptr directly, taking into account where in the word it is.
1557  */
1558 
1559 /*
1560  * _AuData16 - Place 16 bit data in the buffer.
1561  *
1562  * "aud" is a pointer to a AuServer.
1563  * "data" is a pointer to the data.
1564  * "len" is the length in bytes of the data.
1565  */
1566 
1567 static do_AuData16(AuServer *aud, short *data, unsigned int len,
1568                    char *packbuffer)
1569 {
1570     AuInt32 *lp,*lpack;
1571     AuInt32 i, nwords,bits;
1572     AuInt32 mask16 = 0x000000000000ffff;
1573 
1574         lp = (AuInt32 *)data;
1575         lpack = (AuInt32 *)packbuffer;
1576 
1577 /*  nwords is the number of 16 bit values to be packed,
1578  *  the low order 16 bits of each word will be packed
1579  *  into 64 bit words
1580  */
1581         nwords = len >> 1;
1582         bits = 48;
1583 
1584         for(i=0;i<nwords;i++){
1585 	   if (bits == 48) *lpack = 0;
1586            *lpack ^= (*lp & mask16) << bits;
1587            bits -= 16 ;
1588            lp++;
1589            if(bits < 0){
1590                lpack++;
1591                bits = 48;
1592            }
1593         }
1594         _AuData(aud, packbuffer, len);
1595 }
1596 
1597 _AuData16 (AuServer *aud, short *data, unsigned int len)
1598 {
1599     char packbuffer[PACKBUFFERSIZE];
1600     unsigned nunits = PACKBUFFERSIZE >> 1;
1601 
1602     for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
1603 	do_AuData16 (aud, data, PACKBUFFERSIZE, packbuffer);
1604     }
1605     if (len) do_AuData16 (aud, data, len, packbuffer);
1606 }
1607 
1608 /*
1609  * _AuData32 - Place 32 bit data in the buffer.
1610  *
1611  * "aud" is a pointer to a AuServer.
1612  * "data" is a pointer to the data.
1613  * "len" is the length in bytes of the data.
1614  */
1615 
1616 static do_AuData32 (AuServer *aud, AuInt32 *data,
1617                     unsigned int len, char *packbuffer)
1618 {
1619     AuInt32 *lp,*lpack;
1620     AuInt32 i,bits,nwords;
1621     AuInt32 mask32 = 0x00000000ffffffff;
1622 
1623         lpack = (AuInt32 *) packbuffer;
1624         lp = data;
1625 
1626 /*  nwords is the number of 32 bit values to be packed
1627  *  the low order 32 bits of each word will be packed
1628  *  into 64 bit words
1629  */
1630         nwords = len >> 2;
1631         bits = 32;
1632 
1633         for(i=0;i<nwords;i++){
1634 	   if (bits == 32) *lpack = 0;
1635            *lpack ^= (*lp & mask32) << bits;
1636            bits = bits ^32;
1637            lp++;
1638            if(bits)
1639               lpack++;
1640         }
1641         _AuData(aud, packbuffer, len);
1642 }
1643 
1644 _AuData32 (AuServer *aud, AuInt32 *data, unsigned int len)
1645 {
1646     char packbuffer[PACKBUFFERSIZE];
1647     unsigned nunits = PACKBUFFERSIZE >> 2;
1648 
1649     for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
1650 	do_AuData32 (aud, data, PACKBUFFERSIZE, packbuffer);
1651     }
1652     if (len) do_AuData32 (aud, data, len, packbuffer);
1653 }
1654 
1655 #endif /* WORD64 */
1656 
1657 
1658 
1659 /*
1660  * aud->qfree - free the queue of events, called by AuCloseServer
1661  */
1662 
1663 void _AuFreeQ (AuServer *aud)
1664 {
1665     _AuQEvent *qelt = aud->qfree;
1666 
1667     while (qelt) {
1668 	_AuQEvent *qnxt = qelt->next;
1669 	Aufree ((char *) qelt);
1670 	qelt = qnxt;
1671     }
1672     aud->qfree = NULL;
1673     return;
1674 }
1675 
1676 
1677 /* Make sure this produces the same string as DefineLocal/DefineSelf in xdm.
1678  * Otherwise, Xau will not be able to find your cookies in the Xauthority file.
1679  *
1680  * Note: POSIX says that the ``nodename'' member of utsname does _not_ have
1681  *       to have sufficient information for interfacing to the network,
1682  *       and so, you may be better off using gethostname (if it exists).
1683  */
1684 
1685 #if (defined(_POSIX_SOURCE) && !defined(AIXV3)) || defined(hpux) || defined(USG) || defined(SVR4)
1686 #define NEED_UTSNAME
1687 #include <sys/utsname.h>
1688 #endif
1689 
1690 /*
1691  * _AuGetHostname - similar to gethostname but allows special processing.
1692  */
1693 int _AuGetHostname (char *buf, int maxlen)
1694 {
1695     int len;
1696 
1697 #ifdef NEED_UTSNAME
1698     struct utsname name;
1699 
1700     uname (&name);
1701     len = strlen (name.nodename);
1702     if (len >= maxlen) len = maxlen - 1;
1703     strncpy (buf, name.nodename, len);
1704     buf[len] = '\0';
1705 #else
1706     buf[0] = '\0';
1707     (void) gethostname (buf, maxlen);
1708     buf [maxlen - 1] = '\0';
1709     len = strlen(buf);
1710 #endif /* NEED_UTSNAME */
1711     return len;
1712 }
1713 
1714 
1715 
1716 #if (MSKCNT > 4)
1717 /*
1718  * This is a macro if MSKCNT <= 4
1719  */
1720 int
1721 _AuANYSET(AuInt32 *src)
1722 {
1723     int i;
1724 
1725     for (i=0; i<MSKCNT; i++)
1726 	if (src[ i ])
1727 	    return (1);
1728     return (0);
1729 }
1730 #endif
1731 
1732 
1733 #ifdef CRAY
1734 #define HAS_FAKE_IOV
1735 /*
1736  * Cray UniCOS does not have readv and writev so we emulate
1737  */
1738 #include <sys/socket.h>
1739 
1740 int _AuReadV (int fd, struct iovec *iov, int iovcnt)
1741 {
1742   struct msghdr hdr;
1743 
1744   hdr.msg_iov = iov;
1745   hdr.msg_iovlen = iovcnt;
1746   hdr.msg_accrights = 0;
1747   hdr.msg_accrightslen = 0;
1748   hdr.msg_name = 0;
1749   hdr.msg_namelen = 0;
1750 
1751   return (recvmsg (fd, &hdr, 0));
1752 }
1753 
1754 int _AuWriteV (int fd, struct iovec *iov, int iovcnt)
1755 {
1756   struct msghdr hdr;
1757 
1758   hdr.msg_iov = iov;
1759   hdr.msg_iovlen = iovcnt;
1760   hdr.msg_accrights = 0;
1761   hdr.msg_accrightslen = 0;
1762   hdr.msg_name = 0;
1763   hdr.msg_namelen = 0;
1764 
1765   return (sendmsg (fd, &hdr, 0));
1766 }
1767 
1768 #endif /* CRAY */
1769 
1770 #if defined(SYSV) && defined(SYSV386) && !defined(STREAMSCONN) || defined(WIN32)
1771 #define HAS_FAKE_IOV
1772 /*
1773  * SYSV/386 does not have readv so we emulate
1774  */
1775 #ifndef WIN32
1776 #include <sys/uio.h>
1777 #endif /* !WIN32 */
1778 
1779 int _AuReadV (int fd, struct iovec *iov, int iovcnt)
1780 {
1781   int i, len, total;
1782   char *base;
1783 
1784   errno = 0;
1785   for (i=0, total=0;  i<iovcnt;  i++, iov++) {
1786     len = iov->iov_len;
1787     base = iov->iov_base;
1788     while (len > 0) {
1789       int nbytes;
1790 #ifndef WIN32
1791       nbytes = read(fd, base, len);
1792 #else /* WIN32 */
1793       nbytes = recv(fd, base, len, 0);
1794 #endif /* WIN32 */
1795       if (nbytes < 0 && total == 0)  return -1;
1796       if (nbytes <= 0)  return total;
1797       errno = 0;
1798       len   -= nbytes;
1799       total += nbytes;
1800       base  += nbytes;
1801     }
1802   }
1803   return total;
1804 }
1805 
1806 #ifdef WIN32
1807 int _AuWriteV (int fd, struct iovec *iov, int iovcnt)
1808 {
1809   int i, len, total;
1810   char *base;
1811 
1812   errno = 0;
1813   for (i=0, total=0;  i<iovcnt;  i++, iov++) {
1814     len = iov->iov_len;
1815     base = iov->iov_base;
1816     while (len > 0) {
1817       int nbytes;
1818       nbytes = send(fd, base, len, 0);
1819       if (nbytes < 0 && total == 0)  return -1;
1820       if (nbytes <= 0)  return total;
1821       errno = 0;
1822       len   -= nbytes;
1823       total += nbytes;
1824       base  += nbytes;
1825     }
1826   }
1827   return total;
1828 }
1829 #endif /* WIN32 */
1830 
1831 #endif /* SYSV && SYSV386 && !STREAMSCONN */
1832 
1833 #if defined(STREAMSCONN)
1834 
1835 #define HAS_FAKE_IOV
1836 /*
1837  * Copyright 1988, 1989 AT&T, Inc.
1838  *
1839  * Permission to use, copy, modify, and distribute this software and its
1840  * documentation for any purpose and without fee is hereby granted, provided
1841  * that the above copyright notice appear in all copies and that both that
1842  * copyright notice and this permission notice appear in supporting
1843  * documentation, and that the name of AT&T not be used in advertising
1844  * or publicity pertaining to distribution of the software without specific,
1845  * written prior permission.  AT&T makes no representations about the
1846  * suitability of this software for any purpose.  It is provided "as is"
1847  * without express or implied warranty.
1848  *
1849  * AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
1850  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL AT&T
1851  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1852  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
1853  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1854  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1855  *
1856  */
1857 
1858 /*
1859  iovec.c (C source file)
1860 	Acc: 575557389 Mon Mar 28 08:03:09 1988
1861 	Mod: 575557397 Mon Mar 28 08:03:17 1988
1862 	Sta: 575557397 Mon Mar 28 08:03:17 1988
1863 	Owner: 2011
1864 	Group: 1985
1865 	Permissions: 664
1866 */
1867 /*
1868 	START USER STAMP AREA
1869 */
1870 /*
1871 	END USER STAMP AREA
1872 */
1873 
1874 extern char _AusTypeOfStream[];
1875 extern Austream _AusStream[];
1876 
1877 #define MAX_WORKAREA 4096
1878 static char workarea[MAX_WORKAREA];
1879 
1880 
1881 
1882 int
1883 _AuReadV (int fd, struct iovec v[], int n)
1884 {
1885   int i, rc, len, size = 0;
1886   char * buf = workarea;
1887   char * p;
1888 
1889   if (n <= 0 || n > 16)
1890     {
1891       errno = EINVAL;
1892       return (-1);
1893     }
1894   for (i = 0; i < n; ++i)
1895     {
1896       if ((len = v[i].iov_len) < 0 || v[i].iov_base == NULL)
1897         {
1898           errno = EINVAL;
1899           return (-1);
1900         }
1901       size += len;
1902     }
1903   if ((size > MAX_WORKAREA) && ((buf = malloc (size)) == NULL))
1904     {
1905       errno = EINVAL;
1906       return (-1);
1907     }
1908   if((rc = (*_AusStream[_AusTypeOfStream[fd]].ReadFromStream)(fd, buf, size,
1909                                                               BUFFERING))> 0)
1910     {
1911       for (i = 0, p = buf; i < n; ++i)
1912         {
1913           memcpy (v[i].iov_base, p, len = v[i].iov_len);
1914           p += len;
1915         }
1916     }
1917   if (size > MAX_WORKAREA)
1918     free (buf);
1919 
1920   return (rc);
1921 }
1922 
1923 int
1924 _AuWriteV (int fd, struct iovec v[], int n)
1925 {
1926   int i, rc, len, size = 0;
1927   char * buf = workarea;
1928   char * p;
1929 
1930   if (n <= 0 || n > 16)
1931     {
1932       errno = EINVAL;
1933       return (-1);
1934     }
1935   for (i = 0; i < n; ++i)
1936     {
1937       if ((len = v[i].iov_len) < 0 || v[i].iov_base == NULL)
1938         {
1939           errno = EINVAL;
1940           return (-1);
1941         }
1942       size += len;
1943     }
1944 
1945   if ((size > MAX_WORKAREA) && ((buf = malloc (size)) == NULL))
1946     {
1947       errno = EINVAL;
1948       return (-1);
1949     }
1950   for (i = 0, p = buf; i < n; ++i)
1951     {
1952       memcpy (p, v[i].iov_base, len = v[i].iov_len);
1953       p += len;
1954     }
1955   rc = (*_AusStream[_AusTypeOfStream[fd]].WriteToStream)(fd, buf, size);
1956 
1957   if (size > MAX_WORKAREA)
1958     free (buf);
1959 
1960   return (rc);
1961 }
1962 
1963 
1964 
1965 #endif /* STREAMSCONN */
1966 
1967 #ifndef HAS_FAKE_IOV
1968 int
1969 _AuReadV (int fd, struct iovec v[], int n)
1970 {
1971   return(readv(fd, v, n));
1972 }
1973 
1974 int
1975 _AuWriteV (int fd, struct iovec v[], int n)
1976 {
1977   return(writev(fd, v, n));
1978 }
1979 #endif /* HAS_FAKE_IOV */
1980 
1981 AuSyncHandlerRec *
1982 AuRegisterSyncHandler(AuServer *aud, AuSyncHandlerCallback callback,
1983                       AuPointer data)
1984 {
1985     AuSyncHandlerRec *handler;
1986 
1987     if (!(handler = (AuSyncHandlerRec *) Aumalloc(sizeof(AuSyncHandlerRec))))
1988 	return NULL;
1989 
1990     handler->callback = callback;
1991     handler->data = data;
1992 
1993     _AuAddToLinkedList(aud->synchandler, handler);
1994 
1995     return handler;
1996 }
1997 
1998 void
1999 AuUnregisterSyncHandler(AuServer *aud, AuSyncHandlerRec *handler)
2000 {
2001     _AuRemoveFromLinkedList(aud->synchandler, handler);
2002     Aufree(handler);
2003 }
2004 
2005 void
2006 _AuDoSyncHandle(AuServer *aud)
2007 {
2008     AuSyncHandlerRec *p = aud->synchandler,
2009                    *next;
2010 
2011     while (p)
2012     {
2013 	next = p->next;
2014 	(*p->callback) (aud, p, p->data);
2015 	p = next;
2016     }
2017 }
2018