📄 dcpgpkt.c
字号:
do {
if (gmachine(0) != POK) /* Spin with no timeout */
return(-1);
} while (nbuffers >= nwindows);
/*--------------------------------------------------------------------*/
/* Place packet in table and mark unacked */
/*--------------------------------------------------------------------*/
MEMCPY(outbuf[sbu], data, len);
/*--------------------------------------------------------------------*/
/* Handle short packets. */
/*--------------------------------------------------------------------*/
xmitlen[sbu] = s_pktsize;
if (variablepacket)
while ( ((len * 2) < (short) xmitlen[sbu]) && (xmitlen[sbu] > MINPKT) )
xmitlen[sbu] /= 2;
if ( xmitlen[sbu] < MINPKT )
{
printmsg(0,"gsendpkt: Bad packet size %d, "
"data length %d",
xmitlen[sbu], len);
xmitlen[sbu] = MINPKT;
}
delta = xmitlen[sbu] - len;
if (delta > 127)
{
MEMMOVE(outbuf[sbu] + 2, outbuf[sbu], len);
MEMSET(outbuf[sbu]+len+2, 0, delta - 2);
/* Pad with nulls. Ugh. */
outbuf[sbu][0] = (unsigned char) ((delta & 0x7f) | 0x80);
outbuf[sbu][1] = (unsigned char) (delta >> 7);
} /* if (delta > 127) */
else if (delta > 0 )
{
MEMMOVE(outbuf[sbu] + 1, outbuf[sbu], len);
outbuf[sbu][0] = (unsigned char) delta;
MEMSET(outbuf[sbu]+len+1, 0, delta - 1);
/* Pad with nulls. Ugh. */
} /* else if (delta > 0 ) */
/*--------------------------------------------------------------------*/
/* Mark packet */
/*--------------------------------------------------------------------*/
outlen[sbu] = len;
ftimer[sbu] = time(nil(long));
nbuffers++;
/*--------------------------------------------------------------------*/
/* send it */
/*--------------------------------------------------------------------*/
gspack(DATA, rwl, swu, outlen[sbu], xmitlen[sbu], outbuf[sbu]);
swu = nextpkt(swu); /* Bump send window */
sbu = nextbuf( sbu ); /* Bump to next send buffer */
#ifdef _DEBUG
debuglevel = savedebug;
#endif
return(0);
} /*gsendpkt*/
/*--------------------------------------------------------------------*/
/* g e o f p k t */
/* */
/* Transmit EOF to the other system */
/*--------------------------------------------------------------------*/
short geofpkt( void )
{
if ((*sendpkt)("", 0)) /* Empty packet == EOF */
return DCP_FAILED;
else
return DCP_OK;
} /* geofpkt */
/*--------------------------------------------------------------------*/
/* g w r m s g */
/* */
/* Send a message to remote system */
/*--------------------------------------------------------------------*/
short gwrmsg( char *s )
{
for( ; strlen(s) >= s_pktsize; s += s_pktsize)
{
short result = (*sendpkt)(s, (short) s_pktsize);
if (result)
return result;
}
return (*sendpkt)(s, (short) (strlen(s) + 1));
} /* gwrmsg */
/*--------------------------------------------------------------------*/
/* g r d m s g */
/* */
/* Read a message from the remote system */
/*--------------------------------------------------------------------*/
short grdmsg( char *s)
{
for ( ;; )
{
short len;
short result = (*getpkt)( s, &len );
if (result || (s[len-1] == '\0'))
return result;
s += len;
} /* for */
} /* grdmsg */
/********** Packet Machine ********** RH Lamb 3/87 */
/*--------------------------------------------------------------------*/
/* g m a c h i n e */
/* */
/* Ideally we would like to fork this process off in an */
/* infinite loop and send and receive packets through "inbuf" */
/* and "outbuf". Can't do this in MS-DOS so we setup "getpkt" */
/* and "sendpkt" to call this routine often and return only */
/* when the input buffer is empty thus "blocking" the packet- */
/* machine task. */
/*--------------------------------------------------------------------*/
static short gmachine(const short timeout )
{
static time_t idletimer = 0;
boolean done = FALSE; /* True = drop out of machine loop */
boolean close = FALSE; /* True = terminate connection upon
exit */
boolean inseq = TRUE; /* True = Count next out of sequence
packet as an error */
while ( !done )
{
boolean resend = FALSE; /* True = resend data packets */
boolean donak = FALSE; /* True = NAK the other system */
unsigned long packet_no = remote_stats.packets;
short pkttype, rack, rseq, rlen, rbuf, i1;
time_t now;
#ifdef UDEBUG
if ( debuglevel >= 7 ) /* Optimize processing a little bit */
{
printmsg(10, "* send %d %d < W < %d %d, "
"receive %d %d < W < %d, "
"error %d, packet %d",
swl, sbl, swu, sbu, rwl, rbl, rwu, nerr,
(long) remote_stats.packets);
/*--------------------------------------------------------------------*/
/* Waiting for ACKs for swl to swu-1. Next pkt to send=swu */
/* rwl=expected pkt */
/*--------------------------------------------------------------------*/
}
#endif
/*--------------------------------------------------------------------*/
/* Attempt to retrieve a packet and handle it */
/*--------------------------------------------------------------------*/
pkttype = grpack(&rack, &rseq, &rlen, inbuf[nextbuf(rbl)], timeout);
time(&now);
switch (pkttype) {
case CLOSE:
remote_stats.packets++;
printmsg(GDEBUG, "**got CLOSE");
close = done = TRUE;
break;
case DCP_EMPTY:
printmsg(timeout ? GDEBUG : 8, "**got EMPTY");
if (bmodemflag[MODEM_CD] && !CD())
{
printmsg(0,"gmachine: Modem carrier lost");
nerr++;
close = TRUE;
}
if ( terminate_processing )
{
printmsg(0,"gmachine: User aborted processing");
close = TRUE;
}
if (ftimer[sbl])
{
#ifdef UDEBUG
printmsg(6, "---> seq, elapst %d %ld", sbl,
ftimer[sbl] - now);
#endif
if ( ftimer[sbl] <= (now - M_gPacketTimeout))
{
printmsg(4, "*** timeout %d (%ld)",
sbl, (long) remote_stats.packets);
/* Since "g" is "go-back-N", when we time out we
must send the last N pkts in order. The generalized
sliding window scheme relaxes this reqirment. */
nerr++;
timeouts++;
resend = TRUE;
} /* if */
} /* if */
done = TRUE;
break;
case DATA:
printmsg(5, "**got DATA %d %d", rack, rseq);
i1 = nextpkt(rwl); /* (R+1)%8 <-- -->(R+W)%8 */
if (i1 == rseq) {
lazynak--;
remote_stats.packets++;
idletimer = now;
rwl = i1;
rbl = nextbuf( rbl );
inseq = arrived[rbl] = TRUE;
inlen[rbl] = rlen;
printmsg(5, "*** ACK d %d %d", rwl, rbl);
gspack(ACK, rwl, 0, 0, 0, NULL);
done = TRUE; /* return to caller when finished */
/* in a mtask system, unneccesary */
} else {
if (inseq || ( now > (idletimer + M_gPacketTimeout)))
{
donak = TRUE; /* Only flag first out of sequence
packet as error, since we know
following ones also bad */
outsequence++;
inseq = FALSE;
}
printmsg(GDEBUG, "*** unexpect %d ne %d (%d - %d)",
rseq, i1, rwl, rwu);
} /* else */
if ( swl == swu ) /* We waiting for an ACK? */
break; /* No --> Skip ACK processing */
/* else Fall through to ACK case */
case NAK:
case ACK:
if (pkttype == NAK)
{
nerr++;
naksin++;
printmsg(5, "**got NAK %d", rack);
resend = TRUE;
}
else if (pkttype == ACK)
printmsg(5, "**got ACK %d", rack);
while(between(swl, rack, swu))
{ /* S<-- -->(S+W-1)%8 */
remote_stats.packets++;
printmsg(5, "*** ACK %d", swl);
ftimer[sbl] = 0;
idletimer = now;
nbuffers--;
done = TRUE; /* Get more data for input */
swl = nextpkt(swl);
sbl = nextbuf(sbl);
} /* while */
if (!done && (pkttype == ACK)) /* Find packet? */
{
printmsg(GDEBUG,"*** ACK for bad packet %d (%d - %d)",
rack, swl, swu);
} /* if */
break;
case DCP_ERROR:
printmsg(GDEBUG, "*** got BAD CHK");
naksout++;
donak = TRUE;
lazynak = 0; /* Always NAK bad checksum */
break;
default:
screwups++;
nerr++;
printmsg(GDEBUG, "*** got SCREW UP");
break;
} /* switch */
/*--------------------------------------------------------------------*/
/* If we received an NAK or timed out, resend data packets */
/*--------------------------------------------------------------------*/
if ( resend )
for (rack = swl,
rbuf = sbl;
between(swl, rack, swu);
rack = nextpkt(rack), rbuf = nextbuf( rbuf ))
{ /* resend rack->(swu-1) */
resends++;
if ( outbuf[rbuf] == NULL )
{
printmsg(0,"gmachine: Transmit of NULL packet (%d %d)",
rwl, rbuf);
panic();
}
if ( xmitlen[rbuf] == 0 )
{
printmsg(0,"gmachine: Transmit of 0 length packet (%d %d)",
rwl, rbuf);
panic();
}
gspack(DATA, rwl, rack, outlen[rbuf], xmitlen[rbuf], outbuf[rbuf]);
printmsg(5, "*** resent %d", rack);
idletimer = ftimer[rbuf] = now;
} /* for */
/*--------------------------------------------------------------------*/
/* If we have an error and have not recently sent a NAK, do so now. */
/* We then reset our counter so we receive at least a window full of */
/* packets before sending another NAK */
/*--------------------------------------------------------------------*/
if ( donak )
{
nerr++;
if ( (lazynak < 1) || (now > (idletimer + M_gPacketTimeout)))
{
printmsg(5, "*** NAK d %d", rwl);
gspack(NAK, rwl, 0, 0, 0, NULL);
naksout++;
idletimer = now;
lazynak = nwindows + 1;
} /* if ( lazynak < 1 ) */
} /* if ( donak ) */
/*--------------------------------------------------------------------*/
/* Update error counter if needed */
/*--------------------------------------------------------------------*/
if ((close || (packet_no != remote_stats.packets)) && (nerr > 0))
{
printmsg(GDEBUG,"gmachine: Packet %ld had %ld errors during transfer",
remote_stats.packets, (long) nerr);
remote_stats.errors += nerr;
nerr = 0;
}
/*--------------------------------------------------------------------*/
/* If we have an excessive number of errors, drop out of the */
/* loop */
/*--------------------------------------------------------------------*/
if (nerr >= M_MaxErr)
{
printmsg(0,
"gmachine: Consecutive error limit of %d exceeded, %d total errors",
M_MaxErr, nerr + remote_stats.errors);
done = close = TRUE;
gstats();
}
} /* while */
/*--------------------------------------------------------------------*/
/* Return to caller, gracefully terminating packet machine if */
/* requested */
/*--------------------------------------------------------------------*/
if ( close )
{
gspack(CLOSE, 0, 0, 0, 0, NULL);
return CLOSE;
}
else
return POK;
} /*gmachine*/
/*************** FRAMING *****************************/
/*
g s p a c k
Send a packet
type=type yyy=pkrec xxx=timesent len=length<=s_pktsize data=*data
ret(0) always
*/
static void gspack(short type,
short yyy,
short xxx,
short len,
unsigned short xmit,
#if defined(BIT32ENV)
char *data)
#else
char UUFAR *input)
#endif
{
unsigned short check, i;
unsigned char header[HDRSIZE];
#if !defined(BIT32ENV)
char *data; // Local data buffer address
if ( input == NULL )
data = NULL; // Make consistent with real buffer
else { // Only copy if non-NULL
data = gspkt;
MEMCPY( data, input, xmit );
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -