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 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 74 eturnon() 75 { 76 esig=signal(SIGALRM, ealarm); 77 return(0); 78 } 79 80 int 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 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 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 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 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 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 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 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 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 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 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 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