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 1994 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" 32 33 #include "uucp.h" 34 35 #ifdef E_PROTOCOL 36 37 #ifndef MIN 38 #define MIN(a,b) (((a)<(b))?(a):(b)) 39 #endif 40 41 #if defined(BSD4_2) || defined (ATTSVR4) 42 #include <netinet/in.h> 43 #endif /* BSD4_2 || ATTSVR4 */ 44 45 #define EBUFSIZ 1024 46 #define EMESGLEN 20 47 48 #define TBUFSIZE 1024 49 #define TPACKSIZE 512 50 51 extern long lseek(); /* Find offset into the file. */ 52 static jmp_buf Failbuf; 53 extern int erdblk(); 54 extern unsigned msgtime; 55 56 static char Erdstash[EBUFSIZ]; 57 static int Erdlen; 58 59 /* 60 * error-free channel protocol 61 */ 62 /* ARGSUSED */ 63 static void 64 ealarm(sig) 65 int sig; 66 { 67 longjmp(Failbuf, 1); 68 } 69 static void (*esig)(); 70 71 /* 72 * turn on protocol timer 73 */ 74 int 75 eturnon() 76 { 77 esig=signal(SIGALRM, ealarm); 78 return(0); 79 } 80 81 int 82 eturnoff() 83 { 84 signal(SIGALRM, esig); 85 return(0); 86 } 87 88 /* 89 * write message across link 90 * type -> message type 91 * str -> message body (ascii string) 92 * fn -> link file descriptor 93 * return 94 * FAIL -> write failed 95 * SUCCESS -> write succeeded 96 */ 97 int 98 ewrmsg(type, str, fn) 99 register char *str; 100 int fn; 101 char type; 102 { 103 return(etwrmsg(type, str, fn, 0)); 104 } 105 106 /* 107 * read message from link 108 * str -> message buffer 109 * fn -> file descriptor 110 * return 111 * FAIL -> read timed out 112 * SUCCESS -> ok message in str 113 */ 114 int 115 erdmsg(str, fn) 116 register char *str; 117 { 118 return(etrdmsg(str, fn, 0)); 119 } 120 121 /* 122 * read data from file fp1 and write 123 * on link 124 * fp1 -> file descriptor 125 * fn -> link descriptor 126 * returns: 127 * FAIL ->failure in link 128 * SUCCESS -> ok 129 */ 130 int 131 ewrdata(fp1, fn) 132 register FILE *fp1; 133 int fn; 134 { 135 register int ret; 136 int fd1; 137 int len; 138 unsigned long bytes; 139 char bufr[EBUFSIZ]; 140 struct stat statbuf; 141 off_t msglen; 142 char cmsglen[EMESGLEN]; 143 off_t startPoint; /* Offset from begining of the file in 144 * case we are restarting from a check 145 * point. 146 */ 147 148 if (setjmp(Failbuf)) { 149 DEBUG(7, "ewrdata failed\n%s", ""); 150 return(FAIL); 151 } 152 bytes = 0L; 153 fd1 = fileno(fp1); 154 fstat(fd1, &statbuf); 155 startPoint = lseek(fd1, 0L, 1); 156 if (startPoint < 0) 157 { 158 DEBUG(7, "ewrdata lseek failed. Errno=%d\n", errno); 159 return(FAIL); 160 } 161 msglen = statbuf.st_size - startPoint; 162 if (msglen < 0) 163 { 164 DEBUG(7, "ewrdata: startPoint past end of file.\n%s", ""); 165 return(FAIL); 166 } 167 sprintf(cmsglen, "%ld", (long) msglen); 168 DEBUG(9, "ewrdata writing %d ...", sizeof(cmsglen)); 169 alarm(msgtime); 170 ret = (*Write)(fn, cmsglen, sizeof(cmsglen)); 171 alarm(0); 172 DEBUG(9, "ret %d\n", ret); 173 if (ret != sizeof(cmsglen)) 174 return(FAIL); 175 DEBUG(7, "ewrdata planning to send %ld bytes to remote.\n", msglen); 176 while ((len = read( fd1, bufr, EBUFSIZ )) > 0) { 177 DEBUG(9, "ewrdata writing %d ...", len); 178 alarm(msgtime); 179 bytes += len; 180 putfilesize(bytes); 181 ret = (*Write)(fn, bufr, (unsigned) len); 182 alarm(0); 183 DEBUG(9, "ewrdata ret %d\n", ret); 184 if (ret != len) 185 return(FAIL); 186 if ((msglen -= len) <= 0) 187 break; 188 } 189 if (len < 0 || (len == 0 && msglen != 0)) return(FAIL); 190 return(SUCCESS); 191 } 192 193 /* 194 * read data from link and 195 * write into file 196 * fp2 -> file descriptor 197 * fn -> link descriptor 198 * returns: 199 * SUCCESS -> ok 200 * FAIL -> failure on link 201 */ 202 int 203 erddata(fn, fp2) 204 register FILE *fp2; 205 { 206 register int ret; 207 int fd2; 208 char bufr[EBUFSIZ]; 209 int len; 210 long msglen, bytes; 211 char cmsglen[EMESGLEN], *cptr, *erdptr = Erdstash; 212 213 DEBUG(9, "erddata wants %d\n", sizeof(cmsglen)); 214 if (Erdlen > 0) { 215 DEBUG(9, "%d bytes stashed\n", Erdlen); 216 if (Erdlen >= sizeof(cmsglen)) { 217 memcpy(cmsglen, erdptr, sizeof(cmsglen)); 218 Erdlen -= sizeof(cmsglen); 219 erdptr += sizeof(cmsglen); 220 ret = len = 0; 221 } else { 222 memcpy(cmsglen, Erdstash, Erdlen); 223 cptr = cmsglen + Erdlen; 224 len = sizeof(cmsglen) - Erdlen; 225 ret = erdblk(cptr, len, fn); 226 Erdlen = 0; 227 } 228 } else { 229 len = sizeof(cmsglen); 230 ret = erdblk(cmsglen, sizeof(cmsglen), fn); 231 } 232 if (ret != len) 233 return(FAIL); 234 ret = SUCCESS; 235 sscanf(cmsglen, "%ld", &msglen); 236 if ( ((msglen-1)/512 +1) > Ulimit ) 237 ret = EFBIG; 238 DEBUG(7, "erddata file is %ld bytes\n", msglen); 239 fd2 = fileno( fp2 ); 240 241 if (Erdlen > 0) { 242 DEBUG(9, "%d bytes stashed\n", Erdlen); 243 if (write(fileno(fp2), erdptr, Erdlen) != Erdlen) 244 return(FAIL); 245 msglen -= Erdlen; 246 Erdlen = 0; 247 DEBUG(7, "erddata remainder is %ld bytes\n", msglen); 248 } 249 250 for (;;) { 251 len = erdblk(bufr, (int) MIN(msglen, EBUFSIZ), fn); 252 DEBUG(9, "erdblk ret %d\n", len); 253 if (len < 0) { 254 DEBUG(7, "erdblk failed\n%s", ""); 255 return(FAIL); 256 } 257 bytes += len; 258 putfilesize(bytes); 259 if ((msglen -= len) < 0) { 260 DEBUG(7, "erdblk read too much\n%s", ""); 261 return(FAIL); 262 } 263 /* this write is to file -- use write(2), not (*Write) */ 264 if ( ret == SUCCESS && write( fd2, bufr, len ) != len ) { 265 ret = errno; 266 DEBUG(7, "erddata: write to file failed, errno %d\n", ret); 267 } 268 if (msglen == 0) 269 break; 270 } 271 return(ret); 272 } 273 274 /* 275 * read block from link 276 * reads are timed 277 * blk -> address of buffer 278 * len -> size to read 279 * fn -> link descriptor 280 * returns: 281 * FAIL -> link error timeout on link 282 * i -> # of bytes read (must not be 0) 283 */ 284 int 285 erdblk(blk, len, fn) 286 register char *blk; 287 { 288 register 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 trdmsg(str, fn) 326 char *str; 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 twrmsg(type, str, fn) 341 char type; 342 char *str; 343 { 344 return(etwrmsg(type, str, fn, TPACKSIZE)); 345 } 346 347 /* 348 * read data from file fp1 and write on link 349 * fp1 -> file descriptor 350 * fn -> link descriptor 351 * returns: 352 * FAIL ->failure in link 353 * SUCCESS -> ok 354 */ 355 twrdata(fp1, fn) 356 register FILE *fp1; 357 int fn; 358 { 359 register 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 trddata(fn, fp2) 404 register FILE *fp2; 405 { 406 register 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 etrdmsg(str, fn, i) 447 register char *str; 448 register int i; 449 { 450 register int len; 451 int nullterm = 0; 452 char *null, *argstr; 453 454 455 if (i == 0) { 456 DEBUG(9, "etrdmsg looking for null terminator\n", 0); 457 nullterm++; 458 i = EBUFSIZ; 459 argstr = str; 460 } 461 462 if(setjmp(Failbuf)) { 463 DEBUG(7, "timeout (%d sec)\n", msgtime); 464 return(FAIL); 465 } 466 467 alarm(msgtime); 468 for (;;) { 469 DEBUG(9, "etrdmsg want %d ...", i); 470 len = (*Read)(fn, str, i); 471 DEBUG(9, "got %d\n", len); 472 if (len == 0) 473 continue; /* timeout will get this */ 474 if (len < 0) { 475 alarm(0); 476 return(FAIL); 477 } 478 str += len; 479 i -= len; 480 if (nullterm) { 481 /* no way can a msg be as long as EBUFSIZ-1 ... */ 482 *str = 0; 483 null = strchr(argstr, '\0'); 484 if (null != str) { 485 null++; /* start of stash */ 486 memcpy(Erdstash + Erdlen, null, str - null); 487 Erdlen += str - null; 488 break; 489 } else 490 argstr = str; 491 } else { 492 if (i == 0) 493 break; 494 } 495 } 496 alarm(0); 497 return(SUCCESS); 498 } 499 500 /* 501 * write message across link 502 * type -> message type 503 * str -> message body (ascii string) 504 * fn -> link file descriptor 505 * len -> if non-zero, amount to write; 506 o.w., write up to '\0' (inclusive) 507 * return 508 * FAIL -> write failed 509 * SUCCESS -> write succeeded 510 */ 511 etwrmsg(type, str, fn, len) 512 char type; 513 register 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