/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
#include "uucp.h"
#ifdef E_PROTOCOL
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#if defined(BSD4_2) || defined (ATTSVR4)
#include <netinet/in.h>
#endif /* BSD4_2 || ATTSVR4 */
#define EBUFSIZ 1024
#define EMESGLEN 20
#define TBUFSIZE 1024
#define TPACKSIZE 512
extern long lseek(); /* Find offset into the file. */
static jmp_buf Failbuf;
extern int erdblk();
extern unsigned msgtime;
static char Erdstash[EBUFSIZ];
static int Erdlen;
/*
* error-free channel protocol
*/
/* ARGSUSED */
static void
ealarm(sig)
int sig;
{
longjmp(Failbuf, 1);
}
static void (*esig)();
/*
* turn on protocol timer
*/
int
eturnon()
{
esig=signal(SIGALRM, ealarm);
return(0);
}
int
eturnoff()
{
signal(SIGALRM, esig);
return(0);
}
/*
* write message across link
* type -> message type
* str -> message body (ascii string)
* fn -> link file descriptor
* return
* FAIL -> write failed
* SUCCESS -> write succeeded
*/
int
ewrmsg(type, str, fn)
char *str;
int fn;
char type;
{
return(etwrmsg(type, str, fn, 0));
}
/*
* read message from link
* str -> message buffer
* fn -> file descriptor
* return
* FAIL -> read timed out
* SUCCESS -> ok message in str
*/
int
erdmsg(str, fn)
char *str;
{
return(etrdmsg(str, fn, 0));
}
/*
* read data from file fp1 and write
* on link
* fp1 -> file descriptor
* fn -> link descriptor
* returns:
* FAIL ->failure in link
* SUCCESS -> ok
*/
int
ewrdata(fp1, fn)
FILE *fp1;
int fn;
{
int ret;
int fd1;
int len;
unsigned long bytes;
char bufr[EBUFSIZ];
struct stat statbuf;
off_t msglen;
char cmsglen[EMESGLEN];
off_t startPoint; /* Offset from begining of the file in
* case we are restarting from a check
* point.
*/
if (setjmp(Failbuf)) {
DEBUG(7, "ewrdata failed\n%s", "");
return(FAIL);
}
bytes = 0L;
fd1 = fileno(fp1);
fstat(fd1, &statbuf);
startPoint = lseek(fd1, 0L, 1);
if (startPoint < 0)
{
DEBUG(7, "ewrdata lseek failed. Errno=%d\n", errno);
return(FAIL);
}
msglen = statbuf.st_size - startPoint;
if (msglen < 0)
{
DEBUG(7, "ewrdata: startPoint past end of file.\n%s", "");
return(FAIL);
}
sprintf(cmsglen, "%ld", (long) msglen);
DEBUG(9, "ewrdata writing %d ...", sizeof(cmsglen));
alarm(msgtime);
ret = (*Write)(fn, cmsglen, sizeof(cmsglen));
alarm(0);
DEBUG(9, "ret %d\n", ret);
if (ret != sizeof(cmsglen))
return(FAIL);
DEBUG(7, "ewrdata planning to send %ld bytes to remote.\n", msglen);
while ((len = read( fd1, bufr, EBUFSIZ )) > 0) {
DEBUG(9, "ewrdata writing %d ...", len);
alarm(msgtime);
bytes += len;
putfilesize(bytes);
ret = (*Write)(fn, bufr, (unsigned) len);
alarm(0);
DEBUG(9, "ewrdata ret %d\n", ret);
if (ret != len)
return(FAIL);
if ((msglen -= len) <= 0)
break;
}
if (len < 0 || (len == 0 && msglen != 0)) return(FAIL);
return(SUCCESS);
}
/*
* read data from link and
* write into file
* fp2 -> file descriptor
* fn -> link descriptor
* returns:
* SUCCESS -> ok
* FAIL -> failure on link
*/
int
erddata(fn, fp2)
FILE *fp2;
{
int ret;
int fd2;
char bufr[EBUFSIZ];
int len;
long msglen, bytes;
char cmsglen[EMESGLEN], *cptr, *erdptr = Erdstash;
DEBUG(9, "erddata wants %d\n", sizeof(cmsglen));
if (Erdlen > 0) {
DEBUG(9, "%d bytes stashed\n", Erdlen);
if (Erdlen >= sizeof(cmsglen)) {
memcpy(cmsglen, erdptr, sizeof(cmsglen));
Erdlen -= sizeof(cmsglen);
erdptr += sizeof(cmsglen);
ret = len = 0;
} else {
memcpy(cmsglen, Erdstash, Erdlen);
cptr = cmsglen + Erdlen;
len = sizeof(cmsglen) - Erdlen;
ret = erdblk(cptr, len, fn);
Erdlen = 0;
}
} else {
len = sizeof(cmsglen);
ret = erdblk(cmsglen, sizeof(cmsglen), fn);
}
if (ret != len)
return(FAIL);
ret = SUCCESS;
sscanf(cmsglen, "%ld", &msglen);
if ( ((msglen-1)/512 +1) > Ulimit )
ret = EFBIG;
DEBUG(7, "erddata file is %ld bytes\n", msglen);
fd2 = fileno( fp2 );
if (Erdlen > 0) {
DEBUG(9, "%d bytes stashed\n", Erdlen);
if (write(fileno(fp2), erdptr, Erdlen) != Erdlen)
return(FAIL);
msglen -= Erdlen;
Erdlen = 0;
DEBUG(7, "erddata remainder is %ld bytes\n", msglen);
}
for (;;) {
len = erdblk(bufr, (int) MIN(msglen, EBUFSIZ), fn);
DEBUG(9, "erdblk ret %d\n", len);
if (len < 0) {
DEBUG(7, "erdblk failed\n%s", "");
return(FAIL);
}
/*
* handle the case for remote socket close.
*/
if (len == 0) {
ret = errno;
DEBUG(7, "erddata: remote socket closed, errno %d\n",
ret);
break;
}
bytes += len;
putfilesize(bytes);
if ((msglen -= len) < 0) {
DEBUG(7, "erdblk read too much\n%s", "");
return(FAIL);
}
/* this write is to file -- use write(2), not (*Write) */
if ( ret == SUCCESS && write( fd2, bufr, len ) != len ) {
ret = errno;
DEBUG(7, "erddata: write to file failed, errno %d\n", ret);
}
if (msglen == 0)
break;
}
return(ret);
}
/*
* read block from link
* reads are timed
* blk -> address of buffer
* len -> size to read
* fn -> link descriptor
* returns:
* FAIL -> link error timeout on link
* i -> # of bytes read (must not be 0)
*/
int
erdblk(blk, len, fn)
char *blk;
{
int i, ret;
if(setjmp(Failbuf)) {
DEBUG(7, "timeout (%d sec)\n", msgtime);
return(FAIL);
}
alarm(msgtime);
for (i = 0; i < len; i += ret) {
DEBUG(9, "erdblk ask %d ", len - i);
if ((ret = (*Read)(fn, blk, (unsigned) len - i)) < 0) {
alarm(0);
DEBUG(7, "erdblk read failed\n%s", "");
return(FAIL);
}
DEBUG(9, "erdblk got %d\n", ret);
if (ret == 0)
break;
blk += ret;
}
alarm(0);
return(i);
}
struct tbuf {
long t_nbytes;
char t_data[TBUFSIZE];
};
/*
* read message from link
* str -> message buffer
* fn -> file descriptor
* return
* FAIL -> read timed out
* SUCCESS -> ok message in str
*/
int
trdmsg(str, fn)
char *str;
{
return(etrdmsg(str, fn, TPACKSIZE));
}
/*
* write message across link
* type -> message type
* str -> message body (ascii string)
* fn -> link file descriptor
* return
* FAIL -> write failed
* SUCCESS -> write succeeded
*/
int
twrmsg(type, str, fn)
char type;
char *str;
{
return(etwrmsg(type, str, fn, TPACKSIZE));
}
/*
* read data from file fp1 and write on link
* fp1 -> file descriptor
* fn -> link descriptor
* returns:
* FAIL ->failure in link
* SUCCESS -> ok
*/
int
twrdata(fp1, fn)
FILE *fp1;
int fn;
{
int ret;
int len;
unsigned long bytes;
struct tbuf bufr;
struct stat statbuf;
if (setjmp(Failbuf)) {
DEBUG(7, "twrdata failed\n", 0);
return(FAIL);
}
fstat(fileno(fp1), &statbuf);
bytes = 0L;
while ((len = read(fileno(fp1), bufr.t_data, TBUFSIZE)) > 0) {
bufr.t_nbytes = htonl((long)len);
DEBUG(7, "twrdata writing %d ...", len);
bytes += len;
putfilesize(bytes);
len += sizeof(long);
alarm(msgtime);
ret = (*Write)(fn, (char *)&bufr, (unsigned) len);
alarm(0);
DEBUG(7, "ret %d\n", ret);
if (ret != len)
return(FAIL);
if (len != TBUFSIZE+sizeof(long))
break;
}
bufr.t_nbytes = 0;
alarm(msgtime);
ret = write(fn, (char *)&bufr, sizeof(long));
alarm(0);
if (ret != sizeof(long))
return FAIL;
return(SUCCESS);
}
/*
* read data from link and write into file
* fp2 -> file descriptor
* fn -> link descriptor
* returns:
* SUCCESS -> ok
* FAIL -> failure on link
*/
int
trddata(fn, fp2)
FILE *fp2;
{
int len, nread;
long Nbytes;
unsigned long bytes = 0L;
char bufr[TBUFSIZE];
for (;;) {
len = erdblk((char *)&Nbytes, sizeof(Nbytes), fn);
DEBUG(7, "trddata ret %d\n", len);
if (len != sizeof(Nbytes))
return(FAIL);
Nbytes = ntohl(Nbytes);
DEBUG(7,"trddata expecting %ld bytes\n", Nbytes);
nread = Nbytes;
if (nread == 0)
break;
len = erdblk(bufr, nread, fn);
if (len != Nbytes)
return(FAIL);
bytes += len;
putfilesize(bytes);
if (write(fileno(fp2), bufr, len) != len)
return(FAIL);
}
return(SUCCESS);
}
/*
* read message from link
* str -> message buffer
* fn -> file descriptor
* i -> if non-zero, amount to read; o.w., read up to '\0'
* return
* FAIL -> read timed out
* SUCCESS -> ok message in str
*
* 'e' is fatally flawed -- in a byte stream world, rdmsg can pick up
* the cmsglen on a R request. if this happens, we stash the excess
* where rddata can pick it up.
*/
int
etrdmsg(str, fn, i)
char *str;
int i;
{
int len;
int nullterm = 0;
char *null, *argstr;
if (i == 0) {
DEBUG(9, "etrdmsg looking for null terminator\n", 0);
nullterm++;
i = EBUFSIZ;
argstr = str;
}
if(setjmp(Failbuf)) {
DEBUG(7, "timeout (%d sec)\n", msgtime);
return(FAIL);
}
alarm(msgtime);
for (;;) {
DEBUG(9, "etrdmsg want %d ...", i);
len = (*Read)(fn, str, i);
DEBUG(9, "got %d\n", len);
if (len == 0)
continue; /* timeout will get this */
if (len < 0) {
alarm(0);
return(FAIL);
}
str += len;
i -= len;
if (nullterm) {
/* no way can a msg be as long as EBUFSIZ-1 ... */
*str = 0;
null = strchr(argstr, '\0');
if (null != str) {
null++; /* start of stash */
memcpy(Erdstash + Erdlen, null, str - null);
Erdlen += str - null;
break;
} else
argstr = str;
} else {
if (i == 0)
break;
}
}
alarm(0);
return(SUCCESS);
}
/*
* write message across link
* type -> message type
* str -> message body (ascii string)
* fn -> link file descriptor
* len -> if non-zero, amount to write;
o.w., write up to '\0' (inclusive)
* return
* FAIL -> write failed
* SUCCESS -> write succeeded
*/
int
etwrmsg(type, str, fn, len)
char type;
char *str;
int fn, len;
{
char bufr[EBUFSIZ], *endstr;
int ret;
bufr[0] = type;
/* point endstr to last character to be sent */
if ((endstr = strchr(str, '\n')) != 0)
*endstr = 0;
else
endstr = str + strlen(str);
memcpy(bufr+1, str, (endstr - str) + 1); /* include '\0' */
if (len == 0)
len = (endstr - str) + 2; /* include bufr[0] and '\0' */
else
bufr[len-1] = 0; /* 't' needs this terminator */
if (setjmp(Failbuf)) {
DEBUG(7, "etwrmsg write failed\n", 0);
return(FAIL);
}
DEBUG(9, "etwrmsg want %d ... ", len);
alarm(msgtime);
ret = (*Write)(fn, bufr, (unsigned) len);
alarm(0);
DEBUG(9, "sent %d\n", ret);
if (ret != len)
return(FAIL);
return(SUCCESS);
}
#endif /* E_PROTOCOL */