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