📄 pctcp.c
字号:
*/
int tcp_open( tcp_Socket *s, word lport, longword ina, word port, dataHandler_t datahandler )
{
largecheck( s, sizeof( tcp_Socket )); /* stack space warnings */
tcp_unthread(s); /* just in case not totally closed */
memset( s, 0, sizeof( tcp_Socket));
s->rdata = s->rddata;
s->maxrdatalen = tcp_MaxBufSize;
s->ip_type = TCP_PROTO;
// S. Lawson - _mss is *IP DATAGRAM* size, set TCP MSS here
// s->mss = _mss;
s->mss = _mss - sizeof( in_Header ) - sizeof ( tcp_Header );
s->state = tcp_StateSYNSENT;
s->timeout = set_timeout( tcp_LONGTIMEOUT );
s->cwindow = 1;
s->wwindow = 0; /* slow start VJ algorithm */
s->vj_sa = 4; /* about 250 ms */
lport = findfreeport( lport, true ); /* get a nonzero port val (S. Lawson - added true) */
s->myaddr = my_ip_addr;
s->myport = lport;
if ( ina - my_ip_addr <= multihomes ) return( 0 );
if ( ! _arp_resolve(ina, &s->hisethaddr, 0) )
return( 0 );
s->hisaddr = ina;
s->hisport = port;
s->seqnum = intel( set_timeout( 1 )) & 0xffff0000uL;
s->datalen = 0;
s->flags = tcp_FlagSYN;
s->unhappy = true;
s->dataHandler = datahandler;
s->usr_yield = system_yield;
s->frag[0]=s->frag[1]=0L; // S. Lawson
s->safetysig = SAFETYTCP; /* insert into chain */
s->next = tcp_allsocs;
tcp_allsocs = s;
s->rtt_delay = s->rtt_smooth = 18; /* one second startup */
tcp_send(s, __LINE__ );
s->rtt_time = set_timeout( 1 );
return( 1 );
}
/*
* Passive open: listen for a connection on a particular port
*/
int tcp_listen( tcp_Socket *s, word lport, longword ina, word port, dataHandler_t datahandler, word timeout )
{
largecheck( s, sizeof( tcp_Socket ));
tcp_unthread(s); /* just in case not totally closed */
memset( s, 0, sizeof( tcp_Socket));
s->rdata = s->rddata;
s->maxrdatalen = tcp_MaxBufSize;
s->ip_type = TCP_PROTO;
// S. Lawson - _mss is *IP DATAGRAM* size, set TCP MSS here
// s->mss = _mss;
s->mss = _mss - sizeof( in_Header ) - sizeof ( tcp_Header );
s->cwindow = 1;
s->wwindow = 0; /* slow start VJ algorithm */
/* s->vj_sa = 36; /* about 250 ms */
/* tcpwinfix -- mdurkin */
s->vj_sa = 4; /* about 250 ms */ /* was wrong val 95.05.02 */
s->state = tcp_StateLISTEN;
if ( !timeout ) s->timeout = 0; /* forever... */
else s->timeout = set_timeout( timeout );
lport = findfreeport( lport, true ); /* get a nonzero port val (S. Lawson - added true)*/
s->myport = lport;
s->hisport = port;
s->hisaddr = ina;
s->seqnum = intel( (word)(s));
s->datalen = 0;
s->flags = 0;
s->unhappy = false;
s->dataHandler = datahandler;
s->usr_yield = system_yield;
s->frag[0]=s->frag[1]=0L; // S. Lawson
s->safetysig = SAFETYTCP; /* insert into chain */
s->next = tcp_allsocs;
tcp_allsocs = s;
return( 1 );
}
static udp_close( udp_Socket *ds )
{
udp_Socket *s, **sp;
sp = &udp_allsocs;
for (;;) {
s = *sp;
if ( s == ds ) {
*sp = s->next;
break;
}
if ( !s ) break;
if ( ! s->err_msg ) s->err_msg = "UDP Close called";
sp = &s->next;
}
return( 0 );
}
/*
* Send a FIN on a particular port -- only works if it is open
* Must still allow receives
*/
static void tcp_close( tcp_Socket *s )
{
if ( s->ip_type != TCP_PROTO )
return;
if ( s->state == tcp_StateESTAB ||
s->state == tcp_StateESTCL ||
s->state == tcp_StateSYNREC )
{
if ( s->datalen ) /* must first flush all data */
{
s->flags |= tcp_FlagPUSH | tcp_FlagACK;
if ( s->state < tcp_StateESTCL )
{
s->state = tcp_StateESTCL;
tcp_sendsoon( s );
}
}
else
{ /* really closing */
s->flags = tcp_FlagACK | tcp_FlagFIN;
if (!s->err_msg)
s->err_msg = "Connection closed normally";
s->state = tcp_StateFINWT1;
s->timeout = set_timeout( tcp_TIMEOUT ); /* should be a pretty lengthy time */ /* S. Lawson - make longer */
tcp_send( s, __LINE__ );
}
s->unhappy = true;
}
else if (s->state == tcp_StateCLOSWT )
{ /* need to ack the fin and get on with it */
s->timeout = set_timeout( LASTACK_TIMEOUT ); // Added AGW 6 Jan 2001
s->state = tcp_StateLASTACK;
s->flags |= tcp_FlagFIN;
tcp_send( s, __LINE__ );
s->unhappy = true;
// S. Lawson - Added per (10-Jun 1997, GV)
}
else if (s->state == tcp_StateSYNSENT)
{
s->state = tcp_StateCLOSED;
tcp_unthread (s); /* unlink failed connect */
}
}
/*
* Abort a tcp connection
*/
static void tcp_abort( tcp_Socket *s )
{
if (!s->err_msg) s->err_msg = "TCP_ABORT";
if ( s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED ) {
s->flags = tcp_FlagRST | tcp_FlagACK ;
s->unhappy = true;
tcp_send(s, __LINE__);
}
s->unhappy = false;
s->datalen = 0;
s->ip_type = 0;
s->state = tcp_StateCLOSED;
/* if (s->dataHandler) s->dataHandler(s, 0, -1); */
tcp_unthread(s);
}
void sock_abort( sock_type *s )
{
if ( s->tcp.ip_type == TCP_PROTO )
tcp_abort( (tcp_Socket *)s );
else
udp_close( (udp_Socket *)s );
}
/*
* tcp_sendsoon - schedule a transmission pretty soon
* - this one has an imperfection at midnight, but it
* is not significant to the connection performance
*/
void tcp_sendsoon( tcp_Socket *s )
{
longword temp;
if (s->ip_type == TCP_PROTO ) {
temp = set_ttimeout( 1 );
if ( temp == s->rtt_time && s->rto < 2 && s->recent == 0 ) {
s->karn_count = 0;
tcp_send( s, __LINE__ );
s->recent = 1;
return;
}
if ((s->unhappy || s->datalen > 0 || s->karn_count == 1)
&& (s->rtt_time < temp && s->rtt_time != 0)) // S. Lawson - handle 0
return;
s->rtt_time = set_ttimeout( 1 + (s->rto >> 4) );
s->karn_count = 1;
}
}
/*
* Retransmitter - called periodically to perform tcp retransmissions
*/
static longword retran_strat = 0L; /* timeout retran strategy */
static void tcp_Retransmitter( void )
{
tcp_Socket *s;
/* only do this once per RETRAN_STRAT_TIME milliseconds */
if ( !chk_timeout( retran_strat ))
return;
retran_strat = set_ttimeout( RETRAN_STRAT_TIME );
for ( s = tcp_allsocs; s; s = s->next ) {
// S. Lawson - possible to be closed but still queued
if ( s->state==tcp_StateCLOSED ) {
if ( s->rdatalen == 0) tcp_unthread(s);
continue;
}
if ( s->datalen > 0 || s->unhappy || s->karn_count == 1 ) {
/* retransmission strategy */
// S. Lawson - clear the timeout once it fires (thanks GV)
#ifdef NOTUSED
if ( chk_timeout( s->rtt_time)) {
#else
if ( s->rtt_time && chk_timeout( s->rtt_time )) {
s->rtt_time = 0;
#endif
#ifdef DEBUG
if(debug_on >1) printf("regular retran TO set unacked back to 0 from %u\n", s->unacked);
#endif //DEBUG
/* strategy handles closed windows J.D. + E.E. */
if (s->window == 0 && s->karn_count == 2)
s->window = 1;
if ( s->karn_count == 0 ) {
/* if really did timeout */
s->karn_count = 2;
s->unacked = 0;
/* use the backed off rto - implied, no code necessary */
/* reduce the transmit window */
s->cwindow = ((s->cwindow + 1) * 3) >> 2;
if ( s->cwindow == 0 ) s->cwindow = 1;
s->wwindow = 0;
}
if (s->datalen)
s->flags |= tcp_FlagPUSH | tcp_FlagACK;
tcp_send(s, __LINE__);
}
/* EE 99.08.23 */
if ( s->datatimer )
if ( chk_timeout( s->datatimer )) {
sock_abort( (sock_type *) s );
}
}
/* handle inactive tcp timeouts */
if ( sock_inactive && s->inactive_to ) {
if ( chk_timeout( s->inactive_to)) {
/* this baby has timed out */
s->err_msg = "Connection timed out - no activity";
sock_close( (sock_type *) s );
}
}
if ( s->timeout && chk_timeout( s->timeout)) {
if ( s->state == tcp_StateTIMEWT ) {
s->state = tcp_StateCLOSED;
tcp_unthread(s);
break;
} else if (s->state != tcp_StateESTAB && s->state != tcp_StateESTCL ) {
s->err_msg = "Timeout, aborting";
tcp_abort(s);
break;
}
}
}
/* do our various daemons */
if ( wattcpd ) (*wattcpd)();
}
/*
* Unthread a socket from the tcp socket list, if it's there
*/
static void tcp_unthread( tcp_Socket *ds )
{
tcp_Socket *s, **sp;
if (!ds->rdatalen || (ds->state > tcp_StateESTCL))
ds->ip_type = 0; /* fail io */
ds->state = tcp_StateCLOSED; /* tcp_tick needs this */
sp = &tcp_allsocs;
for (;;) {
s = *sp;
if ( s == ds )
{
*sp = s->next;
continue; /* unthread multiple copies if necessary */
}
if ( !s ) break;
sp = &s->next;
}
}
/*
* tcp_tick - called periodically by user application
* - returns 1 when our socket closes (S. Lawson - wrong: 0)
* - called with socket parameter or NULL
*/
int tcp_tick( sock_type *s )
{
in_Header *ip;
static longword timeout = 0;
static longword start = 0;
extern int dhcp_expired(void); /* S. Lawson - in pcbootp.c */
/* int x; */
int packettype;
/* S. Lawson - handle DHCP lease expiration */
if (dhcp_expired()) {
if ( s ) s->udp.err_msg = "DHCP lease expired";
return 0;
}
/* finish off dead sockets */
if ( s ) {
if (( s->tcp.ip_type == TCP_PROTO ) &&
( s->tcp.state == tcp_StateCLOSED ) &&
( s->tcp.rdatalen == 0 )) {
tcp_unthread( & s->tcp );
s->tcp.ip_type = 0;
}
}
/* plan our next retransmit */
if ( !timeout )
timeout = make_timeout( tcp_RETRANSMITTIME );
while ( (ip = (in_Header *)_eth_arrived( (word *) &packettype )) != NULL )
{
start = *realclock;
switch ( packettype )
{
case /*0x800*/ 0x008 :
/* do IP */
if ( checksum(ip, in_GetHdrlenBytes(ip)) == 0xffff ) {
switch ( ip->proto ) {
case TCP_PROTO :
tcp_handler(ip);
break;
case UDP_PROTO :
udp_handler(ip);
break;
case ICMP_PROTO :
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -