📄 pctcp.c
字号:
{
s->hisport = srcPort; /* remember his IP-address */
s->hisaddr = source; /* and src-port */
s->myaddr = destin; /* socket is now active */
break;
}
}
DEBUG_RX (s, ip);
if (!s)
{
if (!(flags & tcp_FlagRST)) /* don't answer RST */
TCP_RESET (NULL, ip, tcp);
else if ((flags & tcp_FlagACK) && /* got ACK,RST */
(s = tcp_findseq(ip,tcp)) != NULL) /* ACK = SEQ + 1 */
tcp_sockreset (s, 1); /* e.g. a firewall is sending */
STAT (tcpstats.tcps_drops++); /* RST for server on inside */
return (NULL);
}
/* Restart idle-timer
*/
if (sock_inactive && !(s->locflags & LF_RCVTIMEO))
s->inactive_to = set_timeout (1000 * sock_inactive);
if (flags & tcp_FlagRST) /* got reset code */
{
tcp_sockreset (s, 0);
return (NULL);
}
tcp_rtt_wind (s); /* update retrans timer, windows etc. */
if (_tcp_fsm(&s,ip) && /* do input tcp state-machine */
s->unhappy) /* if "unhappy", retransmit soon */
TCP_SENDSOON (s);
return (s);
}
#endif /* !USE_UDP_ONLY */
/*
* Handler for incoming udp packets.
*/
static udp_Socket *udp_handler (const in_Header *ip, BOOL broadcast)
{
udp_Socket *s;
udp_Header *udp;
tcp_PseudoHeader ph;
WORD len, dstPort, srcPort;
DWORD destin = intel (ip->destination);
BOOL ip_bcast = broadcast || /* link-layer broadcast */
is_ip_brdcast(ip); /* (directed) ip-broadcast */
#if !defined(USE_MULTICAST)
/* dst = ip number
* or 255.255.255.255
* or sin_mask.255.255
* This is the only really gross hack in the multicasting stuff.
* I'll fix it as soon as I can figure out what I want to do here.
* -JRM 8/1/93
*/
if (!ip_bcast && /* not a broadcast packet */
destin - my_ip_addr > multihomes && /* not my address */
my_ip_addr) /* and I know my address */
{
DEBUG_RX (NULL, ip);
return (NULL);
}
#endif
len = in_GetHdrLen (ip);
udp = (udp_Header*) ((BYTE*)ip + len); /* udp segment pointer */
len = intel16 (udp->length);
if (len < sizeof(*udp))
{
DEBUG_RX (NULL, ip);
STAT (udpstats.udps_hdrops++);
return (NULL);
}
srcPort = intel16 (udp->srcPort);
dstPort = intel16 (udp->dstPort);
/* demux to active sockets
*/
for (s = _udp_allsocs; s; s = s->next)
{
if (s->safetysig != SAFETYUDP)
{
outsnl (_LANG("udp-socket error in udp_handler()"));
DEBUG_RX (s, ip);
return (NULL);
}
if (!ip_bcast &&
(s->hisport != 0) &&
(dstPort == s->myport) &&
(srcPort == s->hisport) &&
((destin & sin_mask) == (s->myaddr & sin_mask)) &&
(intel(ip->source) == s->hisaddr))
break;
}
if (!s)
{
/* demux to passive sockets
*/
for (s = _udp_allsocs; s; s = s->next)
{
if ((s->hisaddr == 0 || s->hisaddr == 0xFFFFFFFFUL) &&
dstPort == s->myport)
{
if (s->hisaddr == 0)
{
s->hisaddr = intel (ip->source);
s->hisport = srcPort;
SET_PEER_MAC_ADDR (s, ip);
/* take on value of expected destination
* unless it is broadcast
*/
if (!ip_bcast)
s->myaddr = destin;
}
break;
}
}
}
DEBUG_RX (s, ip);
#if defined(USE_MULTICAST)
if (!s)
{
/* demux to multicast sockets
*/
for (s = _udp_allsocs; s; s = s->next)
{
if (s->hisport != 0 &&
s->hisaddr == destin &&
dstPort == s->myport &&
is_multicast(destin))
break;
}
}
#endif
if (!s)
{
/* Demux to broadcast sockets.
*/
for (s = _udp_allsocs; s; s = s->next)
{
if (s->hisaddr == (DWORD)-1 && dstPort == s->myport)
break;
}
}
if (!s) /* no demultiplexer found anything */
{
if (debug_on)
outs (_LANG("discarding..."));
if ((destin - my_ip_addr <= multihomes) && my_ip_addr)
{
if (!ip_bcast && /* broadcast? */
srcPort != DOM_DST_PORT) /* from a nameserver? */
icmp_unreach (ip, 3); /* send port unreachable */
if (ip_bcast)
STAT (udpstats.udps_noportbcast++);
else STAT (udpstats.udps_noport++);
}
return (NULL);
}
/* these parameters are used for things other than just checksums
*/
memset (&ph, 0, sizeof(ph));
ph.src = ip->source; /* already network order */
ph.dst = ip->destination;
ph.protocol = UDP_PROTO;
ph.length = udp->length;
ph.checksum = checksum (udp, len);
if (udp->checksum && (s->sockmode & UDP_MODE_NOCHK) == 0)
{
if (checksum(&ph,sizeof(ph)) != 0xFFFF)
{
if (debug_on)
outsnl (_LANG("bad udp checksum"));
STAT (udpstats.udps_badsum++);
return (s);
}
}
/* Process user data. 0-byte probe is legal for s->protoHandler.
*/
{
BYTE *data = (BYTE*)(udp+1);
len -= sizeof(*udp);
if (s->protoHandler)
(*s->protoHandler) (s, data, len, &ph, udp);
/* save first received packet rather than latest */
else if (len > 0 && s->rdatalen == 0)
{
if (len > s->maxrdatalen) /* truncate data :-( */
{
len = s->maxrdatalen;
STAT (udpstats.udps_fullsock++);
}
/* Might overwrite previous data! But hey, this is UDP..
*/
memcpy (s->rdata, data, len);
s->rdatalen = len;
}
}
return (s);
}
/*
* tcp_Retransmit() - called periodically to perform retransmissions.
* - if 'force == 1' do it now.
*/
void tcp_Retransmitter (int force)
{
#if defined(USE_UDP_ONLY)
ARGSUSED (force);
#else
tcp_Socket *s, *next;
static DWORD timeout = 0UL;
/* do this once per tcp_RETRAN_TIME
*/
if (!force && timeout && !chk_timeout(timeout))
return;
timeout = set_timeout (tcp_RETRAN_TIME);
for (s = _tcp_allsocs; s; s = next)
{
next = s->next;
/* possible to be closed but still queued
*/
if (s->state == tcp_StateCLOSED)
{
if (s->rdatalen == 0)
{
maybe_reuse_lport (s);
next = _tcp_unthread (s);
}
continue;
}
if (s->datalen > 0 || s->unhappy || s->karn_count == 1)
{
if (chk_timeout(s->rtt_time)) /* retransmission timeout */
{
s->rtt_time = 0UL; /* stop RTT timer */
#if defined(USE_DEBUG)
if (debug_on > 1)
(*_printf) ("regular retran TO set unacked back to 0 from %u\r\n",
s->unacked);
#endif
/* strategy handles closed windows. JD + EE
*/
if (s->window == 0 && s->karn_count == 2)
s->window = 1;
if (s->karn_count == 0)
{
/* Simple "Slow start" algorithm:
* Use the backed off RTO - implied, no code necessary.
* Reduce the congestion window by 25%
*/
unsigned cwindow = ((unsigned)(s->cwindow + 1) * 3) >> 2;
s->cwindow = cwindow;
if (s->cwindow == 0)
s->cwindow = 1;
s->wwindow = 0; /* dup ACK counter ? */
/* s->snd_ssthresh = s->cwindow * s->max_seg; */ /* !!to-do */
/* if really did timeout
*/
s->karn_count = 2;
s->unacked = 0;
}
if (s->datalen > 0)
s->flags |= (tcp_FlagPUSH | tcp_FlagACK);
if (s->unhappy)
STAT (tcpstats.tcps_rexmttimeo++);
else if (s->flags & tcp_FlagACK)
STAT (tcpstats.tcps_delack++);
(void) TCP_SEND (s);
}
/* handle inactive tcp timeouts (not sending data)
*/
if (chk_timeout(s->datatimer)) /* EE 99.08.23 */
{
s->err_msg = _LANG("Connection timed out - no data sent");
tcp_abort (s);
}
} /* end of retransmission strategy */
/* handle inactive tcp timeouts (not received anything)
*/
if (chk_timeout(s->inactive_to))
{
/* this baby has timed out. Don't do this again.
*/
s->inactive_to = 0UL;
s->err_msg = _LANG("Connection timed out - no activity");
sock_close ((sock_type*)s);
}
else if (chk_timeout(s->timeout))
{
if (s->state == tcp_StateTIMEWT)
{
s->state = tcp_StateCLOSED;
break;
}
else if (s->state != tcp_StateESTAB && s->state != tcp_StateESTCL)
{
s->err_msg = _LANG("Timeout, aborting");
tcp_abort (s);
break;
}
}
}
#endif /* !USE_UDP_ONLY */
}
/*
* ip_handler - do a simple check on IP header
* - Demultiplex packet to correct protocol handler
*/
int _ip_handler (in_Header *ip, BOOL broadcast)
{
sock_type *s = NULL;
if (block_ip || !_chk_ip_header(ip))
return (0);
#if 0
/* to-do: check for LSRR option and replace ip->source
*/ with actual source-address burried in option
* (ref. RFC1122)
#endif
#if defined(USE_BSD_FUNC)
/*
* Match 'ip' against all SOCK_RAW sockets before doing normal
* protocol multiplexing below.
*
* Note: _raw_ip_hook is only set if we have allocated at least
* one SOCK_RAW socket. Don't waste time searching otherwise.
*
* Fix-me: a raw socket may gobble up a packet we're awaiting in
* e.g. resolve().
*/
if (_raw_ip_hook && (*_raw_ip_hook)(ip))
return (1);
#endif
switch (ip->proto)
{
#if !defined(USE_UDP_ONLY)
case TCP_PROTO:
s = (sock_type*) tcp_handler (ip, broadcast);
break;
#endif
case UDP_PROTO:
s = (sock_type*) udp_handler (ip, broadcast);
break;
case ICMP_PROTO:
icmp_handler (ip, broadcast);
break;
#if defined(USE_MULTICAST)
case IGMP_PROTO:
igmp_handler (ip, broadcast);
break;
#endif
default:
if (!broadcast)
{
if (is_local_addr (intel(ip->destination)))
icmp_unreach (ip, 2); /* protocol unreachable */
DEBUG_RX (NULL, ip);
STAT (ipstats.ips_noproto++);
}
return (0);
}
if (s) /* Check if peer allows IP-fragments */
{
if (intel16(ip->frag_ofs) & IP_DF)
s->tcp.locflags |= LF_NOFRAGMENT;
else s->tcp.locflags &= ~LF_NOFRAGMENT;
}
STAT (ipstats.ips_delivered++);
return (1);
}
/*
* tcp_tick - called periodically by user application
* - called with socket parameter or NULL
* - returns 1 when our socket closes
*/
WORD tcp_tick (sock_type *s)
{
static DWORD daemon_timer = 0UL;
#if !defined(USE_UDP_ONLY)
/* finish off dead sockets
*/
if (s)
{
if ((s->tcp.ip_type == TCP_PROTO) &&
(s->tcp.state == tcp_StateCLOSED) &&
(s->tcp.rdatalen == 0))
{
(void) _tcp_unthread (&s->tcp);
s->tcp.ip_type = 0; /* fail further I/O */
}
}
#endif
while (1)
{
WORD eth_type = 0;
BOOL brdcast = FALSE;
void *packet = _eth_arrived (ð_type, &brdcast);
if (!packet) /* packet points to network layer protocol */
break;
switch (eth_type)
{
case IP_TYPE:
_ip_handler ((in_Header*)packet, brdcast);
break;
case ARP_TYPE:
_arp_handler ((arp_Header*)packet);
break;
#if defined(USE_PPPOE)
case PPPOE_DISC_TYPE:
case PPPOE_SESS_TYPE:
pppoe_handler ((struct pppoe_Packet*)packet);
break;
#endif
/* RARP is only used during boot. Not needed here */
}
_eth_free (packet, eth_type);
}
#if defined(USE_MULTICAST)
if (_multicast_on)
check_mcast_reports();
#endif
#if !defined(USE_UDP_ONLY)
tcp_Retransmitter (0); /* check for our outstanding packets */
#endif
if ((daemon_timer == 0UL || chk_timeout(daemon_timer)) && wattcpd)
{
(*wattcpd)(); /* do our various daemons */
daemon_timer = set_timeout (DAEMON_RUN_TIME);
}
return (s ? s->tcp.ip_type : 0);
}
/*
* udp_write()
*/
static int udp_write (udp_Socket *s, const BYTE *data, int len)
{
#include <sys/packon.h>
struct udp_pkt {
in_Header in;
udp_Header udp;
/* BYTE data[]; */
} *pkt;
#include <sys/packoff.h>
tcp_PseudoHeader ph;
in_Header *ip;
udp_Header *udp;
mac_address *dst;
/* build link-layer header
*/
dst = (_pktserial ? NULL : &s->hisethaddr);
pkt = (struct udp_pkt*) _eth_formatpacket (dst, IP_TYPE);
ip = &pkt->in;
udp = &pkt->udp;
/* build udp header
*/
udp->srcPort = intel16 (s->myport);
udp->dstPort = intel16 (s->hisport);
udp->checksum = 0;
udp->length = intel16 (sizeof(*udp)+len);
memcpy (pkt+1, data, len); /* copy 'data' to 'pkt->data[]' */
memset (&ph, 0, sizeof(ph));
ph.src = intel (s->myaddr);
ph.dst = intel (s->hisaddr);
if (!(s->sockmode & UDP_MODE_NOCHK))
{
ph.protocol = UDP_PROTO;
ph.length = udp->length;
ph.checksum = checksum (udp, sizeof(*udp)+len);
udp->checksum = ~checksum (&ph, sizeof(ph));
}
if (!IP_OUTPUT(ip, ph.src, ph.dst, UDP_PROTO, s->ttl,
(BYTE)_default_tos, 0, sizeof(*udp)+len, s))
return (-1);
return (len);
}
/*
* udp_read - read socket data to 'buf', does large buffering
*/
static int udp_read (udp_Socket *s, BYTE *buf, int maxlen)
{
int len = s->rdatalen;
if (maxlen < 0)
maxlen = INT_MAX;
if (len > 0)
{
if (len > maxlen)
len = maxlen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -