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