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(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 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 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 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 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 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 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 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 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 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 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