xref: /titanic_52/usr/src/cmd/lp/lib/msgs/read_fifo.c (revision 1a7c1b724419d3cb5fa6eea75123c6b2060ba31b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.11	*/
32 /* LINTLIBRARY */
33 
34 
35 # include	<errno.h>
36 # include	<string.h>
37 #include <syslog.h>
38 
39 # include	"lp.h"
40 # include	"msgs.h"
41 
42 extern char	Resync[];
43 extern char	Endsync[];
44 static int	Had_Full_Buffer = 1;
45 int		Garbage_Bytes	= 0;
46 int		Garbage_Messages= 0;
47 
48 /*
49 ** A real message is written in one piece, and the write
50 ** is atomic. Thus, even if the O_NDELAY flag is set,
51 ** if we read part of the real message, we can continue
52 ** to read the rest of it in as many steps as we want
53 ** (up to the size of the message, of course!) without
54 ** UNIX returning 0 because no data is available.
55 ** So, a real message doesn't have to be read in one piece,
56 ** which is good since we don't know how much to read!
57 **
58 ** Fake messages, or improperly written messages, don't
59 ** have this nice property.
60 **
61 ** INTERRUPTED READS:
62 **
63 ** If a signal occurs during an attempted read, we can exit.
64 ** The caller can retry the read and we will correctly restart
65 ** it. The correctness of this assertion can be seen by noticing
66 ** that at the beginning of each READ below, we can go back
67 ** to the first statement executed (the first READ below)
68 ** and correctly reexecute the code.
69 **
70 ** If the last writer closed the fifo, we'll read 0 bytes
71 ** (at least on the subsequent read). If we were in the
72 ** middle of reading a message, we were reading a bogus
73 ** message (but see below).
74 **
75 ** If we read less than we expect, it's because we were
76 ** reading a fake message (but see below).
77 **
78 ** HOWEVER: In the last two cases, we may have ONE OR MORE
79 ** REAL MESSAGES snuggled in amongst the trash!
80 **
81 ** All this verbal rambling is preface to let you understand why we
82 ** buffer the data (which is a shame, but necessary).
83 */
84 
85 /*
86 ** As long as we get real messages, we can avoid needless function calls.
87 ** The SYNC argument in this macro should be set if the resynch. bytes
88 ** have been read--i.e. if the rest of the message is trying to be read.
89 ** In this case, if we had not read a full buffer last time, then we
90 ** must be in the middle of a bogus message.
91 */
92 
93 #define UNSYNCHED_READ(N) \
94     if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \
95     { \
96 	switch (_buffer(fifo)) \
97 	{ \
98 	    case -1: \
99 		return (-1); \
100 	    case 0: \
101 		if (fbp->psave_end > fbp->psave) \
102 		    goto SyncUp; \
103 		return (0); \
104 	} \
105     }
106 
107 #define SYNCHED_READ(N) \
108     if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \
109     { \
110 	switch (_buffer(fifo)) \
111 	{ \
112 	    case -1: \
113 		return (-1); \
114 	    case 0: \
115 		if (fbp->psave_end > fbp->psave) \
116 		    goto SyncUp; \
117 		return (0); \
118 	} \
119 	if (!Had_Full_Buffer) \
120 	    goto SyncUp; \
121     }
122 
123 /*
124 ** read_fifo() - READ A BUFFER WITH HEADER AND CHECKSUM
125 */
126 int
127 read_fifo (fifo, buf, size)
128 int		fifo;
129 char		*buf;
130 unsigned int	size;
131 {
132     register fifobuffer_t *fbp;
133     register unsigned int real_chksum,
134 			  chksum,
135 			  real_size;
136 
137     /*
138     ** Make sure we start on a message boundary. The first
139     ** line of defense is to look for the resync. bytes.
140     **
141     ** The "SyncUp" label is global to this routine (below this point)
142     ** and is called whenever we determine that we're out
143     ** of sync. with the incoming bytes.
144     */
145 
146     if (!(fbp=GetFifoBuffer (fifo)))
147 	return	-1;
148 
149     UNSYNCHED_READ (HEAD_RESYNC_LEN);
150     while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1])
151     {
152 SyncUp:
153 #if	defined(TRACE_MESSAGES)
154 	if (trace_messages)
155 		syslog(LOG_DEBUG, "DISCARD %c\n", *fbp->psave);
156 #endif
157 	fbp->psave++;
158 	Garbage_Bytes++;
159 	UNSYNCHED_READ (HEAD_RESYNC_LEN);
160     }
161 
162 
163     /*
164     ** We're sync'd, so read the full header.
165     */
166 
167     SYNCHED_READ (HEAD_LEN);
168 
169 
170     /*
171     ** If the header size is smaller than the minimum size for a header,
172     ** or larger than allowed, we must assume that we really aren't
173     ** synchronized.
174     */
175 
176     real_size = stoh(fbp->psave + HEAD_SIZE);
177     if (real_size < CONTROL_LEN || MSGMAX < real_size)
178     {
179 #if	defined(TRACE_MESSAGES)
180 	if (trace_messages)
181 		syslog(LOG_DEBUG, "BAD SIZE\n");
182 #endif
183 	goto SyncUp;
184     }
185 
186     /*
187     ** We have the header. Now we can finally read the rest of the
188     ** message...
189     */
190 
191     SYNCHED_READ (real_size);
192 
193 
194     /*
195     ** ...but did we read a real message?...
196     */
197 
198     if
199     (
200 	   *(fbp->psave + TAIL_ENDSYNC(real_size)) != Endsync[0]
201 	|| *(fbp->psave + TAIL_ENDSYNC(real_size) + 1) != Endsync[1]
202     )
203     {
204 #if	defined(TRACE_MESSAGES)
205 	if (trace_messages)
206 		syslog(LOG_DEBUG, "BAD ENDSYNC\n");
207 #endif
208 	Garbage_Messages++;
209 	goto SyncUp;
210     }
211 
212     chksum = stoh(fbp->psave + TAIL_CHKSUM(real_size));
213     CALC_CHKSUM (fbp->psave, real_size, real_chksum);
214     if (real_chksum != chksum)
215     {
216 #if	defined(TRACE_MESSAGES)
217 	if (trace_messages)
218 		syslog(LOG_DEBUG, "BAD CHKSUM\n");
219 #endif
220 	Garbage_Messages++;
221 	goto SyncUp;
222     }
223 
224     /*
225     ** ...yes!...but can the caller handle the message?
226     */
227 
228     if (size < real_size)
229     {
230 	errno = E2BIG;
231 	return (-1);
232     }
233 
234 
235     /*
236     ** Yes!! We can finally copy the message into the caller's buffer
237     ** and remove it from our buffer. That wasn't so bad, was it?
238     */
239 
240 #if	defined(TRACE_MESSAGES)
241     if (trace_messages)
242 	syslog(LOG_DEBUG, "MESSAGE: %-.*s", real_size, fbp->psave);
243 #endif
244     (void)memcpy (buf, fbp->psave, real_size);
245     fbp->psave += real_size;
246     return (real_size);
247 }
248 
249 int
250 peek3_2 (fifo)
251 int		fifo;
252 {
253     register fifobuffer_t	*fbp;
254     register unsigned int	real_size;
255 
256     /*
257     ** Make sure we start on a message boundary. The first
258     ** line of defense is to look for the resync. bytes.
259     **
260     ** The "SyncUp" label is global to this routine (below this point)
261     ** and is called whenever we determine that we're out
262     ** of sync. with the incoming bytes.
263     */
264 
265     if (!(fbp=GetFifoBuffer (fifo)))
266 	return	-1;
267     UNSYNCHED_READ (HEAD_RESYNC_LEN);
268     while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1])
269     {
270 SyncUp:
271 	fbp->psave++;
272 	Garbage_Bytes++;
273 	UNSYNCHED_READ (HEAD_RESYNC_LEN);
274     }
275 
276 
277     /*
278     ** We're sync'd, so read the full header.
279     */
280 
281     SYNCHED_READ (HEAD_LEN);
282 
283 
284     /*
285     ** If the header size is smaller than the minimum size for a header,
286     ** or larger than allowed, we must assume that we really aren't
287     ** synchronized.
288     */
289 
290     real_size = stoh(fbp->psave + HEAD_SIZE);
291     if (real_size < CONTROL_LEN || MSGMAX < real_size)
292     {
293 	goto SyncUp;
294     }
295 
296     return(real_size);
297 }
298 
299 static int
300 _buffer (fifo)
301 int	fifo;
302 {
303 	     int	   n, nbytes, count = 0;
304     register fifobuffer_t  *fbp;
305 
306     /*
307     ** As long as we get real messages, and if we chose
308     ** SAVE_SIZE well, we shouldn't have to move the data
309     ** in the "else" branch below: Each time we call "read"
310     ** we aren't likely to get as many bytes as we ask for,
311     ** just as many as are in the fifo, AND THIS SHOULD
312     ** REPRESENT AN INTEGRAL NUMBER OF MESSAGES. Since
313     ** the "read_fifo" routine reads complete messages,
314     ** it will end its read at the end of the message,
315     ** which (eventually) will make "psave_end" == "psave".
316     */
317 
318     /*
319     ** If the buffer is empty, there's nothing to move.
320     */
321     if (!(fbp = GetFifoBuffer (fifo)))
322 	return	-1;
323     if (fbp->psave_end == fbp->psave)
324 	fbp->psave = fbp->psave_end = fbp->save;	/* sane pointers! */
325 
326     /*
327     ** If the buffer has data at the high end, move it down.
328     */
329     else
330     if (fbp->psave != fbp->save)		/* sane pointers! */
331     {
332 	/*
333 	** Move the data still left in the buffer to the
334 	** front, so we can read as much as possible into
335 	** buffer after it.
336 	*/
337 
338 	memmove(fbp->save, fbp->psave, fbp->psave_end - fbp->psave);
339 
340 	fbp->psave_end = fbp->save + (fbp->psave_end - fbp->psave);
341 	fbp->psave = fbp->save;	/* sane	pointers! */
342     }
343 
344     /*
345     ** The "fbp->psave" and "fbp->psave_end" pointers must be in a sane
346     ** state when we get here, in case the "read()" gets interrupted.
347     ** When that happens, we return to the caller who may try
348     ** to restart us! Sane: fbp->psave == fbp->save (HERE!)
349     */
350 
351     nbytes = MSGMAX - (fbp->psave_end - fbp->save);
352 
353     while ((n = read(fifo, fbp->psave_end, nbytes)) == 0 && count < 60)
354     {
355 	(void)	sleep ((unsigned) 1);
356 	count++;
357     }
358 
359     if (n > 0)
360 	fbp->psave_end += n;
361 
362     Had_Full_Buffer = fbp->full;
363     fbp->full = (nbytes == n);
364 
365     return (n);
366 }
367