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