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