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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 #include "uucp.h"
33
34 #ifdef E_PROTOCOL
35
36 #ifndef MIN
37 #define MIN(a,b) (((a)<(b))?(a):(b))
38 #endif
39
40 #if defined(BSD4_2) || defined (ATTSVR4)
41 #include <netinet/in.h>
42 #endif /* BSD4_2 || ATTSVR4 */
43
44 #define EBUFSIZ 1024
45 #define EMESGLEN 20
46
47 #define TBUFSIZE 1024
48 #define TPACKSIZE 512
49
50 extern long lseek(); /* Find offset into the file. */
51 static jmp_buf Failbuf;
52 extern int erdblk();
53 extern unsigned msgtime;
54
55 static char Erdstash[EBUFSIZ];
56 static int Erdlen;
57
58 /*
59 * error-free channel protocol
60 */
61 /* ARGSUSED */
62 static void
ealarm(sig)63 ealarm(sig)
64 int sig;
65 {
66 longjmp(Failbuf, 1);
67 }
68 static void (*esig)();
69
70 /*
71 * turn on protocol timer
72 */
73 int
eturnon()74 eturnon()
75 {
76 esig=signal(SIGALRM, ealarm);
77 return(0);
78 }
79
80 int
eturnoff()81 eturnoff()
82 {
83 signal(SIGALRM, esig);
84 return(0);
85 }
86
87 /*
88 * write message across link
89 * type -> message type
90 * str -> message body (ascii string)
91 * fn -> link file descriptor
92 * return
93 * FAIL -> write failed
94 * SUCCESS -> write succeeded
95 */
96 int
ewrmsg(type,str,fn)97 ewrmsg(type, str, fn)
98 char *str;
99 int fn;
100 char type;
101 {
102 return(etwrmsg(type, str, fn, 0));
103 }
104
105 /*
106 * read message from link
107 * str -> message buffer
108 * fn -> file descriptor
109 * return
110 * FAIL -> read timed out
111 * SUCCESS -> ok message in str
112 */
113 int
erdmsg(str,fn)114 erdmsg(str, fn)
115 char *str;
116 {
117 return(etrdmsg(str, fn, 0));
118 }
119
120 /*
121 * read data from file fp1 and write
122 * on link
123 * fp1 -> file descriptor
124 * fn -> link descriptor
125 * returns:
126 * FAIL ->failure in link
127 * SUCCESS -> ok
128 */
129 int
ewrdata(fp1,fn)130 ewrdata(fp1, fn)
131 FILE *fp1;
132 int fn;
133 {
134 int ret;
135 int fd1;
136 int len;
137 unsigned long bytes;
138 char bufr[EBUFSIZ];
139 struct stat statbuf;
140 off_t msglen;
141 char cmsglen[EMESGLEN];
142 off_t startPoint; /* Offset from begining of the file in
143 * case we are restarting from a check
144 * point.
145 */
146
147 if (setjmp(Failbuf)) {
148 DEBUG(7, "ewrdata failed\n%s", "");
149 return(FAIL);
150 }
151 bytes = 0L;
152 fd1 = fileno(fp1);
153 fstat(fd1, &statbuf);
154 startPoint = lseek(fd1, 0L, 1);
155 if (startPoint < 0)
156 {
157 DEBUG(7, "ewrdata lseek failed. Errno=%d\n", errno);
158 return(FAIL);
159 }
160 msglen = statbuf.st_size - startPoint;
161 if (msglen < 0)
162 {
163 DEBUG(7, "ewrdata: startPoint past end of file.\n%s", "");
164 return(FAIL);
165 }
166 sprintf(cmsglen, "%ld", (long) msglen);
167 DEBUG(9, "ewrdata writing %d ...", sizeof(cmsglen));
168 alarm(msgtime);
169 ret = (*Write)(fn, cmsglen, sizeof(cmsglen));
170 alarm(0);
171 DEBUG(9, "ret %d\n", ret);
172 if (ret != sizeof(cmsglen))
173 return(FAIL);
174 DEBUG(7, "ewrdata planning to send %ld bytes to remote.\n", msglen);
175 while ((len = read( fd1, bufr, EBUFSIZ )) > 0) {
176 DEBUG(9, "ewrdata writing %d ...", len);
177 alarm(msgtime);
178 bytes += len;
179 putfilesize(bytes);
180 ret = (*Write)(fn, bufr, (unsigned) len);
181 alarm(0);
182 DEBUG(9, "ewrdata ret %d\n", ret);
183 if (ret != len)
184 return(FAIL);
185 if ((msglen -= len) <= 0)
186 break;
187 }
188 if (len < 0 || (len == 0 && msglen != 0)) return(FAIL);
189 return(SUCCESS);
190 }
191
192 /*
193 * read data from link and
194 * write into file
195 * fp2 -> file descriptor
196 * fn -> link descriptor
197 * returns:
198 * SUCCESS -> ok
199 * FAIL -> failure on link
200 */
201 int
erddata(fn,fp2)202 erddata(fn, fp2)
203 FILE *fp2;
204 {
205 int ret;
206 int fd2;
207 char bufr[EBUFSIZ];
208 int len;
209 long msglen, bytes;
210 char cmsglen[EMESGLEN], *cptr, *erdptr = Erdstash;
211
212 DEBUG(9, "erddata wants %d\n", sizeof(cmsglen));
213 if (Erdlen > 0) {
214 DEBUG(9, "%d bytes stashed\n", Erdlen);
215 if (Erdlen >= sizeof(cmsglen)) {
216 memcpy(cmsglen, erdptr, sizeof(cmsglen));
217 Erdlen -= sizeof(cmsglen);
218 erdptr += sizeof(cmsglen);
219 ret = len = 0;
220 } else {
221 memcpy(cmsglen, Erdstash, Erdlen);
222 cptr = cmsglen + Erdlen;
223 len = sizeof(cmsglen) - Erdlen;
224 ret = erdblk(cptr, len, fn);
225 Erdlen = 0;
226 }
227 } else {
228 len = sizeof(cmsglen);
229 ret = erdblk(cmsglen, sizeof(cmsglen), fn);
230 }
231 if (ret != len)
232 return(FAIL);
233 ret = SUCCESS;
234 sscanf(cmsglen, "%ld", &msglen);
235 if ( ((msglen-1)/512 +1) > Ulimit )
236 ret = EFBIG;
237 DEBUG(7, "erddata file is %ld bytes\n", msglen);
238 fd2 = fileno( fp2 );
239
240 if (Erdlen > 0) {
241 DEBUG(9, "%d bytes stashed\n", Erdlen);
242 if (write(fileno(fp2), erdptr, Erdlen) != Erdlen)
243 return(FAIL);
244 msglen -= Erdlen;
245 Erdlen = 0;
246 DEBUG(7, "erddata remainder is %ld bytes\n", msglen);
247 }
248
249 for (;;) {
250 len = erdblk(bufr, (int) MIN(msglen, EBUFSIZ), fn);
251 DEBUG(9, "erdblk ret %d\n", len);
252 if (len < 0) {
253 DEBUG(7, "erdblk failed\n%s", "");
254 return(FAIL);
255 }
256
257 /*
258 * handle the case for remote socket close.
259 */
260 if (len == 0) {
261 ret = errno;
262 DEBUG(7, "erddata: remote socket closed, errno %d\n",
263 ret);
264 break;
265 }
266 bytes += len;
267 putfilesize(bytes);
268 if ((msglen -= len) < 0) {
269 DEBUG(7, "erdblk read too much\n%s", "");
270 return(FAIL);
271 }
272 /* this write is to file -- use write(2), not (*Write) */
273 if ( ret == SUCCESS && write( fd2, bufr, len ) != len ) {
274 ret = errno;
275 DEBUG(7, "erddata: write to file failed, errno %d\n", ret);
276 }
277 if (msglen == 0)
278 break;
279 }
280 return(ret);
281 }
282
283 /*
284 * read block from link
285 * reads are timed
286 * blk -> address of buffer
287 * len -> size to read
288 * fn -> link descriptor
289 * returns:
290 * FAIL -> link error timeout on link
291 * i -> # of bytes read (must not be 0)
292 */
293 int
erdblk(blk,len,fn)294 erdblk(blk, len, fn)
295 char *blk;
296 {
297 int i, ret;
298
299 if(setjmp(Failbuf)) {
300 DEBUG(7, "timeout (%d sec)\n", msgtime);
301 return(FAIL);
302 }
303
304 alarm(msgtime);
305 for (i = 0; i < len; i += ret) {
306 DEBUG(9, "erdblk ask %d ", len - i);
307 if ((ret = (*Read)(fn, blk, (unsigned) len - i)) < 0) {
308 alarm(0);
309 DEBUG(7, "erdblk read failed\n%s", "");
310 return(FAIL);
311 }
312 DEBUG(9, "erdblk got %d\n", ret);
313 if (ret == 0)
314 break;
315 blk += ret;
316 }
317 alarm(0);
318 return(i);
319 }
320
321 struct tbuf {
322 long t_nbytes;
323 char t_data[TBUFSIZE];
324 };
325
326 /*
327 * read message from link
328 * str -> message buffer
329 * fn -> file descriptor
330 * return
331 * FAIL -> read timed out
332 * SUCCESS -> ok message in str
333 */
334 int
trdmsg(str,fn)335 trdmsg(str, fn)
336 char *str;
337 {
338 return(etrdmsg(str, fn, TPACKSIZE));
339 }
340
341 /*
342 * write message across link
343 * type -> message type
344 * str -> message body (ascii string)
345 * fn -> link file descriptor
346 * return
347 * FAIL -> write failed
348 * SUCCESS -> write succeeded
349 */
350 int
twrmsg(type,str,fn)351 twrmsg(type, str, fn)
352 char type;
353 char *str;
354 {
355 return(etwrmsg(type, str, fn, TPACKSIZE));
356 }
357
358 /*
359 * read data from file fp1 and write on link
360 * fp1 -> file descriptor
361 * fn -> link descriptor
362 * returns:
363 * FAIL ->failure in link
364 * SUCCESS -> ok
365 */
366 int
twrdata(fp1,fn)367 twrdata(fp1, fn)
368 FILE *fp1;
369 int fn;
370 {
371 int ret;
372 int len;
373 unsigned long bytes;
374 struct tbuf bufr;
375 struct stat statbuf;
376
377 if (setjmp(Failbuf)) {
378 DEBUG(7, "twrdata failed\n", 0);
379 return(FAIL);
380 }
381 fstat(fileno(fp1), &statbuf);
382 bytes = 0L;
383 while ((len = read(fileno(fp1), bufr.t_data, TBUFSIZE)) > 0) {
384 bufr.t_nbytes = htonl((long)len);
385 DEBUG(7, "twrdata writing %d ...", len);
386 bytes += len;
387 putfilesize(bytes);
388 len += sizeof(long);
389 alarm(msgtime);
390 ret = (*Write)(fn, (char *)&bufr, (unsigned) len);
391 alarm(0);
392 DEBUG(7, "ret %d\n", ret);
393 if (ret != len)
394 return(FAIL);
395 if (len != TBUFSIZE+sizeof(long))
396 break;
397 }
398 bufr.t_nbytes = 0;
399 alarm(msgtime);
400 ret = write(fn, (char *)&bufr, sizeof(long));
401 alarm(0);
402 if (ret != sizeof(long))
403 return FAIL;
404 return(SUCCESS);
405 }
406
407 /*
408 * read data from link and write into file
409 * fp2 -> file descriptor
410 * fn -> link descriptor
411 * returns:
412 * SUCCESS -> ok
413 * FAIL -> failure on link
414 */
415 int
trddata(fn,fp2)416 trddata(fn, fp2)
417 FILE *fp2;
418 {
419 int len, nread;
420 long Nbytes;
421 unsigned long bytes = 0L;
422 char bufr[TBUFSIZE];
423
424 for (;;) {
425 len = erdblk((char *)&Nbytes, sizeof(Nbytes), fn);
426 DEBUG(7, "trddata ret %d\n", len);
427 if (len != sizeof(Nbytes))
428 return(FAIL);
429 Nbytes = ntohl(Nbytes);
430 DEBUG(7,"trddata expecting %ld bytes\n", Nbytes);
431 nread = Nbytes;
432 if (nread == 0)
433 break;
434 len = erdblk(bufr, nread, fn);
435 if (len != Nbytes)
436 return(FAIL);
437 bytes += len;
438 putfilesize(bytes);
439 if (write(fileno(fp2), bufr, len) != len)
440 return(FAIL);
441 }
442 return(SUCCESS);
443 }
444
445 /*
446 * read message from link
447 * str -> message buffer
448 * fn -> file descriptor
449 * i -> if non-zero, amount to read; o.w., read up to '\0'
450 * return
451 * FAIL -> read timed out
452 * SUCCESS -> ok message in str
453 *
454 * 'e' is fatally flawed -- in a byte stream world, rdmsg can pick up
455 * the cmsglen on a R request. if this happens, we stash the excess
456 * where rddata can pick it up.
457 */
458
459 int
etrdmsg(str,fn,i)460 etrdmsg(str, fn, i)
461 char *str;
462 int i;
463 {
464 int len;
465 int nullterm = 0;
466 char *null, *argstr;
467
468
469 if (i == 0) {
470 DEBUG(9, "etrdmsg looking for null terminator\n", 0);
471 nullterm++;
472 i = EBUFSIZ;
473 argstr = str;
474 }
475
476 if(setjmp(Failbuf)) {
477 DEBUG(7, "timeout (%d sec)\n", msgtime);
478 return(FAIL);
479 }
480
481 alarm(msgtime);
482 for (;;) {
483 DEBUG(9, "etrdmsg want %d ...", i);
484 len = (*Read)(fn, str, i);
485 DEBUG(9, "got %d\n", len);
486 if (len == 0)
487 continue; /* timeout will get this */
488 if (len < 0) {
489 alarm(0);
490 return(FAIL);
491 }
492 str += len;
493 i -= len;
494 if (nullterm) {
495 /* no way can a msg be as long as EBUFSIZ-1 ... */
496 *str = 0;
497 null = strchr(argstr, '\0');
498 if (null != str) {
499 null++; /* start of stash */
500 memcpy(Erdstash + Erdlen, null, str - null);
501 Erdlen += str - null;
502 break;
503 } else
504 argstr = str;
505 } else {
506 if (i == 0)
507 break;
508 }
509 }
510 alarm(0);
511 return(SUCCESS);
512 }
513
514 /*
515 * write message across link
516 * type -> message type
517 * str -> message body (ascii string)
518 * fn -> link file descriptor
519 * len -> if non-zero, amount to write;
520 o.w., write up to '\0' (inclusive)
521 * return
522 * FAIL -> write failed
523 * SUCCESS -> write succeeded
524 */
525 int
etwrmsg(type,str,fn,len)526 etwrmsg(type, str, fn, len)
527 char type;
528 char *str;
529 int fn, len;
530 {
531 char bufr[EBUFSIZ], *endstr;
532 int ret;
533
534 bufr[0] = type;
535
536 /* point endstr to last character to be sent */
537 if ((endstr = strchr(str, '\n')) != 0)
538 *endstr = 0;
539 else
540 endstr = str + strlen(str);
541
542 memcpy(bufr+1, str, (endstr - str) + 1); /* include '\0' */
543 if (len == 0)
544 len = (endstr - str) + 2; /* include bufr[0] and '\0' */
545 else
546 bufr[len-1] = 0; /* 't' needs this terminator */
547
548
549 if (setjmp(Failbuf)) {
550 DEBUG(7, "etwrmsg write failed\n", 0);
551 return(FAIL);
552 }
553 DEBUG(9, "etwrmsg want %d ... ", len);
554 alarm(msgtime);
555 ret = (*Write)(fn, bufr, (unsigned) len);
556 alarm(0);
557 DEBUG(9, "sent %d\n", ret);
558 if (ret != len)
559 return(FAIL);
560 return(SUCCESS);
561 }
562 #endif /* E_PROTOCOL */
563