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 2005 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#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32/* LINTLIBRARY */
33
34# include	<errno.h>
35# include	<string.h>
36#include <syslog.h>
37
38# include	"lp.h"
39# include	"msgs.h"
40
41extern char	Resync[];
42extern char	Endsync[];
43static int	Had_Full_Buffer = 1;
44int		Garbage_Bytes	= 0;
45int		Garbage_Messages= 0;
46
47static int _buffer(int);
48
49/*
50** A real message is written in one piece, and the write
51** is atomic. Thus, even if the O_NDELAY flag is set,
52** if we read part of the real message, we can continue
53** to read the rest of it in as many steps as we want
54** (up to the size of the message, of course!) without
55** UNIX returning 0 because no data is available.
56** So, a real message doesn't have to be read in one piece,
57** which is good since we don't know how much to read!
58**
59** Fake messages, or improperly written messages, don't
60** have this nice property.
61**
62** INTERRUPTED READS:
63**
64** If a signal occurs during an attempted read, we can exit.
65** The caller can retry the read and we will correctly restart
66** it. The correctness of this assertion can be seen by noticing
67** that at the beginning of each READ below, we can go back
68** to the first statement executed (the first READ below)
69** and correctly reexecute the code.
70**
71** If the last writer closed the fifo, we'll read 0 bytes
72** (at least on the subsequent read). If we were in the
73** middle of reading a message, we were reading a bogus
74** message (but see below).
75**
76** If we read less than we expect, it's because we were
77** reading a fake message (but see below).
78**
79** HOWEVER: In the last two cases, we may have ONE OR MORE
80** REAL MESSAGES snuggled in amongst the trash!
81**
82** All this verbal rambling is preface to let you understand why we
83** buffer the data (which is a shame, but necessary).
84*/
85
86/*
87** As long as we get real messages, we can avoid needless function calls.
88** The SYNC argument in this macro should be set if the resynch. bytes
89** have been read--i.e. if the rest of the message is trying to be read.
90** In this case, if we had not read a full buffer last time, then we
91** must be in the middle of a bogus message.
92*/
93
94#define UNSYNCHED_READ(N) \
95    if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \
96    { \
97	switch (_buffer(fifo)) \
98	{ \
99	    case -1: \
100		return (-1); \
101	    case 0: \
102		if (fbp->psave_end > fbp->psave) \
103		    goto SyncUp; \
104		return (0); \
105	} \
106    }
107
108#define SYNCHED_READ(N) \
109    if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \
110    { \
111	switch (_buffer(fifo)) \
112	{ \
113	    case -1: \
114		return (-1); \
115	    case 0: \
116		if (fbp->psave_end > fbp->psave) \
117		    goto SyncUp; \
118		return (0); \
119	} \
120	if (!Had_Full_Buffer) \
121	    goto SyncUp; \
122    }
123
124/*
125** read_fifo() - READ A BUFFER WITH HEADER AND CHECKSUM
126*/
127int
128read_fifo (fifo, buf, size)
129int		fifo;
130char		*buf;
131unsigned int	size;
132{
133    register fifobuffer_t *fbp;
134    register unsigned int real_chksum,
135			  chksum,
136			  real_size;
137
138    /*
139    ** Make sure we start on a message boundary. The first
140    ** line of defense is to look for the resync. bytes.
141    **
142    ** The "SyncUp" label is global to this routine (below this point)
143    ** and is called whenever we determine that we're out
144    ** of sync. with the incoming bytes.
145    */
146
147    if (!(fbp=GetFifoBuffer (fifo)))
148	return	-1;
149
150    UNSYNCHED_READ (HEAD_RESYNC_LEN);
151    while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1])
152    {
153SyncUp:
154#if	defined(TRACE_MESSAGES)
155	if (trace_messages)
156		syslog(LOG_DEBUG, "DISCARD %c\n", *fbp->psave);
157#endif
158	fbp->psave++;
159	Garbage_Bytes++;
160	UNSYNCHED_READ (HEAD_RESYNC_LEN);
161    }
162
163
164    /*
165    ** We're sync'd, so read the full header.
166    */
167
168    SYNCHED_READ (HEAD_LEN);
169
170
171    /*
172    ** If the header size is smaller than the minimum size for a header,
173    ** or larger than allowed, we must assume that we really aren't
174    ** synchronized.
175    */
176
177    real_size = stoh(fbp->psave + HEAD_SIZE);
178    if (real_size < CONTROL_LEN || MSGMAX < real_size)
179    {
180#if	defined(TRACE_MESSAGES)
181	if (trace_messages)
182		syslog(LOG_DEBUG, "BAD SIZE\n");
183#endif
184	goto SyncUp;
185    }
186
187    /*
188    ** We have the header. Now we can finally read the rest of the
189    ** message...
190    */
191
192    SYNCHED_READ (real_size);
193
194
195    /*
196    ** ...but did we read a real message?...
197    */
198
199    if
200    (
201	   *(fbp->psave + TAIL_ENDSYNC(real_size)) != Endsync[0]
202	|| *(fbp->psave + TAIL_ENDSYNC(real_size) + 1) != Endsync[1]
203    )
204    {
205#if	defined(TRACE_MESSAGES)
206	if (trace_messages)
207		syslog(LOG_DEBUG, "BAD ENDSYNC\n");
208#endif
209	Garbage_Messages++;
210	goto SyncUp;
211    }
212
213    chksum = stoh(fbp->psave + TAIL_CHKSUM(real_size));
214    CALC_CHKSUM (fbp->psave, real_size, real_chksum);
215    if (real_chksum != chksum)
216    {
217#if	defined(TRACE_MESSAGES)
218	if (trace_messages)
219		syslog(LOG_DEBUG, "BAD CHKSUM\n");
220#endif
221	Garbage_Messages++;
222	goto SyncUp;
223    }
224
225    /*
226    ** ...yes!...but can the caller handle the message?
227    */
228
229    if (size < real_size)
230    {
231	errno = E2BIG;
232	return (-1);
233    }
234
235
236    /*
237    ** Yes!! We can finally copy the message into the caller's buffer
238    ** and remove it from our buffer. That wasn't so bad, was it?
239    */
240
241#if	defined(TRACE_MESSAGES)
242    if (trace_messages)
243	syslog(LOG_DEBUG, "MESSAGE: %-.*s", real_size, fbp->psave);
244#endif
245    (void)memcpy (buf, fbp->psave, real_size);
246    fbp->psave += real_size;
247    return (real_size);
248}
249
250int
251peek3_2 (fifo)
252int		fifo;
253{
254    register fifobuffer_t	*fbp;
255    register unsigned int	real_size;
256
257    /*
258    ** Make sure we start on a message boundary. The first
259    ** line of defense is to look for the resync. bytes.
260    **
261    ** The "SyncUp" label is global to this routine (below this point)
262    ** and is called whenever we determine that we're out
263    ** of sync. with the incoming bytes.
264    */
265
266    if (!(fbp=GetFifoBuffer (fifo)))
267	return	-1;
268    UNSYNCHED_READ (HEAD_RESYNC_LEN);
269    while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1])
270    {
271SyncUp:
272	fbp->psave++;
273	Garbage_Bytes++;
274	UNSYNCHED_READ (HEAD_RESYNC_LEN);
275    }
276
277
278    /*
279    ** We're sync'd, so read the full header.
280    */
281
282    SYNCHED_READ (HEAD_LEN);
283
284
285    /*
286    ** If the header size is smaller than the minimum size for a header,
287    ** or larger than allowed, we must assume that we really aren't
288    ** synchronized.
289    */
290
291    real_size = stoh(fbp->psave + HEAD_SIZE);
292    if (real_size < CONTROL_LEN || MSGMAX < real_size)
293    {
294	goto SyncUp;
295    }
296
297    return(real_size);
298}
299
300static int
301_buffer(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