📄 pctcp.c
字号:
if (len > 0)
{
if (buf)
memcpy (buf, s->rdata, len);
s->rdatalen -= len;
if (s->rdatalen)
movmem (s->rdata+len, s->rdata, s->rdatalen);
}
}
return (len);
}
void _udp_cancel (const in_Header *ip, int type, const char *msg, DWORD gateway)
{
WORD srcPort, dstPort;
int len = in_GetHdrLen (ip);
BOOL passive = FALSE;
udp_Header *udp = (udp_Header*) ((BYTE*)ip + len);
udp_Socket *s;
srcPort = intel16 (udp->srcPort);
dstPort = intel16 (udp->dstPort);
for (s = _udp_allsocs; s; s = s->next) /* demux to active sockets */
{
if (s->hisport && dstPort == s->hisport && srcPort == s->myport &&
intel(ip->destination) == s->hisaddr)
break;
}
if (!s) /* check passive sockets */
{
passive = TRUE;
for (s = _udp_allsocs; s; s = s->next)
if (s->hisport == 0 && dstPort == s->myport)
break;
}
if (s)
{
if (s->err_msg == NULL && msg)
s->err_msg = msg;
if (s->sol_callb) /* tell the socket layer about it */
(*s->sol_callb) ((void*)s, type);
if (type == ICMP_REDIRECT && /* handle redirect on active sockets */
!passive)
{
_ip_recursion = 1;
_arp_resolve (gateway, &s->hisethaddr, 1);
_ip_recursion = 0;
}
else if (type != ICMP_TIMXCEED)
{
s->rdatalen = 0; /* will it be unthreaded ? */
s->ip_type = 0;
s->err_msg = _LANG("Port unreachable");
}
}
else
{
/* tell the INADDR_ANY sockets about it
*/
for (s = _udp_allsocs; s; s = s->next)
{
if (s->sol_callb)
(*s->sol_callb) ((void*)s, type);
}
}
}
#if !defined(USE_UDP_ONLY)
void _tcp_cancel (const in_Header *ip, int type, const char *msg, DWORD gateway)
{
tcp_Header *tcp = (tcp_Header*) ((BYTE*)ip + in_GetHdrLen (ip));
tcp_Socket *s;
WORD srcPort = intel16 (tcp->srcPort);
WORD dstPort = intel16 (tcp->dstPort);
/* demux to active sockets
*/
for (s = _tcp_allsocs; s; s = s->next)
{
if (srcPort == s->myport && dstPort == s->hisport &&
intel(ip->destination) == s->hisaddr)
{
switch (type)
{
case ICMP_TIMXCEED:
if (s->ttl < 255)
s->ttl++;
/* FALLTROUGH */
case ICMP_UNREACH:
if (s->stress++ > s->rigid && s->rigid < 100) /* halt it */
{
s->err_msg = msg ? msg : _LANG("ICMP closed connection");
s->rdatalen = 0;
s->datalen = 0;
s->unhappy = FALSE;
tcp_abort (s);
break;
}
/* FALLTROUGH */
case ICMP_SOURCEQUENCH:
s->cwindow = 1; /* slow-down tx-rate */
s->wwindow = 1;
s->vj_sa <<= 2;
s->vj_sd <<= 2;
s->rto <<= 2;
tcp_rtt_add (s, s->rto);
break;
case ICMP_REDIRECT:
/* don't bother handling redirect if we're closing
*/
if (s->state >= tcp_StateFINWT1)
{
if (s->err_msg == NULL && msg)
s->err_msg = msg;
break;
}
_ip_recursion = 1;
_arp_resolve (gateway, &s->hisethaddr, 1);
_ip_recursion = 0;
break;
case ICMP_PARAMPROB:
tcp_abort (s);
break;
}
if (s->sol_callb)
(*s->sol_callb) ((void*)s, type);
}
}
}
/*
* tcp_read - read socket data to 'buf', does large buffering
*/
static int tcp_read (tcp_Socket *s, BYTE *buf, int maxlen)
{
int len = s->rdatalen;
if (maxlen < 0)
maxlen = INT_MAX;
if (len > 0)
{
if (len > maxlen)
len = maxlen;
if (len > 0)
{
if (buf)
memcpy (buf, s->rdata, len);
s->rdatalen -= len;
if (s->missed_seg[0] || s->rdatalen > 0)
{
int diff = 0;
if (s->missed_seg[0] != 0)
{
long ldiff = s->missed_seg[1] - s->acknum;
diff = abs ((int)ldiff);
}
movmem (s->rdata + len, s->rdata, s->rdatalen + diff);
TCP_SENDSOON (s); /* update the window soon */
}
else
tcp_upd_wind (s, __LINE__);
}
}
else if (s->state == tcp_StateCLOSWT)
_tcp_close (s);
return (len);
}
/*
* Write data to a connection.
* Returns number of bytes written, == 0 when no room in socket-buffer
*/
static int tcp_write (tcp_Socket *s, const BYTE *data, UINT len)
{
UINT room;
if (s->state != tcp_StateESTAB)
return (0);
room = tcp_MaxTxBufSize - s->datalen;
if (len > room)
len = room;
if (len > 0)
{
int rc = 0;
memcpy (s->data + s->datalen, data, len);
s->datalen += len;
s->unhappy = TRUE; /* redundant because we have outstanding data */
s->datatimer = set_timeout (1000 * sock_data_timeout); /* EE 99.08.23 */
if (s->sockmode & TCP_LOCAL) /* queue up data, flush on next write */
{
s->sockmode &= ~TCP_LOCAL;
return (len);
}
if (s->sockmode & TCP_MODE_NONAGLE)
rc = TCP_SEND (s);
else
{
/* transmit if first data or reached MTU.
* not true MTU, but better than nothing
*/
if (s->datalen == len || s->datalen > s->max_seg/2)
rc = TCP_SEND (s);
else rc = TCP_SENDSOON (s);
}
if (rc < 0)
return (-1);
}
return (len);
}
/*
* Find the socket with the tripplet:
* DESTADDR=MYADDR,DESTPORT=MYPORT and ACKNUM=SEQNUM+1
*/
static tcp_Socket *tcp_findseq (const in_Header *ip, const tcp_Header *tcp)
{
tcp_Socket *s;
DWORD dstHost = intel (ip->destination);
DWORD ackNum = intel (tcp->acknum);
WORD dstPort = intel16 (tcp->dstPort);
for (s = _tcp_allsocs; s; s = s->next)
{
if (s->hisport != 0 &&
dstHost == s->myaddr &&
dstPort == s->myport &&
ackNum == (s->seqnum+1))
break;
}
return (s);
}
static void tcp_sockreset (tcp_Socket *s, int proxy)
{
char *str = proxy ? "Proxy reset connection"
: "Remote reset connection";
if (debug_on)
outsnl (_LANG(str));
s->datalen = 0; /* Flush Tx buffer */
if (s->state != tcp_StateCLOSED && s->state != tcp_StateLASTACK)
s->rdatalen = 0;
s->err_msg = _LANG (str);
s->state = tcp_StateCLOSED;
s->ip_type = 0; /* 2001.1.18 - make it fail tcp_tick() */
#if defined(USE_BSD_FUNC)
if (_tcp_find_hook)
{
Socket *sock = (Socket*) (*_tcp_find_hook) (s);
if (sock) /* do a "read-wakeup" on the SOCK_STREAM socket */
{
sock->so_state |= SS_CONN_REFUSED;
if (sock->so_error == 0)
sock->so_error = ECONNRESET;
}
}
#endif
(void) _tcp_unthread (s);
}
/*
* tcp_chksum - Check tcp header checksum
*/
static int tcp_chksum (const in_Header *ip, const tcp_Header *tcp, int len)
{
tcp_PseudoHeader ph;
memset (&ph, 0, sizeof(ph));
ph.src = ip->source;
ph.dst = ip->destination;
ph.protocol = TCP_PROTO;
ph.length = intel16 (len);
ph.checksum = checksum (tcp, len);
if (checksum(&ph,sizeof(ph)) == 0xFFFF)
return (1);
STAT (tcpstats.tcps_rcvbadsum++);
if (debug_on)
outsnl (_LANG("bad tcp checksum"));
return (0);
}
/*
* tcp_rtt_wind - Update retransmission timer, VJ algorithm
* and tcp windows.
*/
static void tcp_rtt_wind (tcp_Socket *s)
{
DWORD timeout;
/* update our retransmission stuff (Karn algorithm)
*/
if (s->karn_count == 2) /* Wake up from slow-start */
{
#if defined(USE_DEBUG)
if (debug_on > 1)
(*_printf)("finally got it safely zapped from %u to ????\r\n",
s->unacked);
#endif
}
else if (s->vj_last) /* We expect an immediate response */
{
long dT; /* time since last (re)transmission */
DWORD now;
chk_timeout (0UL); /* update date/date_ms */
now = (long) set_timeout (0);
dT = (long) get_timediff (now, s->vj_last);
if (dT >= 0) /* !!shouldn't this be '> 0' ? */
{
dT -= (DWORD)(s->vj_sa >> 3);
s->vj_sa += (int)dT;
if (dT < 0)
dT = -dT;
dT -= (s->vj_sd >> 2);
s->vj_sd += (int)dT; /* vj_sd = RTTVAR, rtt variance */
if (s->vj_sa > MAX_VJSA) /* vj_sa = SRTT, smoothed rtt */
s->vj_sa = MAX_VJSA;
if (s->vj_sd > MAX_VJSD)
s->vj_sd = MAX_VJSD;
}
#if 0 /* !!to-do: use TimeStamp option values */
if (s->ts_echo && s->ts_echo == s->ts_sent)
{
dT = get_timediff (now, s->ts_echo);
}
else
#else
/* only recompute RTT hence RTO after success
*/
s->rto = tcp_RTO_BASE + (((s->vj_sa >> 2) + (s->vj_sd)) >> 1);
#endif
tcp_rtt_add (s, s->rto);
#if defined(USE_DEBUG)
if (debug_on > 1)
(*_printf)("rto %u sa %u sd %u cwindow %u"
" wwindow %u unacked %u\r\n",
s->rto, s->vj_sa, s->vj_sd, s->cwindow,
s->wwindow, s->unacked);
#endif
}
s->karn_count = 0;
if (s->wwindow != 255)
{
/* A. Iljasov (iljasov@oduurl.ru) suggested this pre-increment
*/
if (++s->wwindow >= s->cwindow)
{
if (s->cwindow != 255)
s->cwindow++;
s->wwindow = 0; /* mdurkin -- added 95.05.02 */
}
}
/* Restart RTT timer or postpone retransmission
* based on calculated RTO. Make sure date/date_ms variables
* are updated close to midnight.
*/
chk_timeout (0UL);
timeout = set_timeout (s->rto + tcp_RTO_ADD);
if (s->rtt_time == 0UL || cmp_timers(s->rtt_time,timeout) < 0)
s->rtt_time = timeout;
s->datatimer = 0UL; /* resetting tx-timer, EE 99.08.23 */
}
/*
* tcp_upd_wind - Check if receive window needs an update.
*/
static void tcp_upd_wind (tcp_Socket *s, unsigned line)
{
UINT winfree = s->maxrdatalen - s->rdatalen;
if (winfree < s->max_seg/2)
_tcp_send (s, __FILE__, line); /* update window now */
}
/*
* TCP option routines.
* Note: Each of these MUST add multiple of 4 byte of options.
*
* Insert MSS option.
*/
static __inline int tcp_opt_maxsegment (tcp_Socket *s, BYTE *opt)
{
*opt++ = TCPOPT_MAXSEG; /* option: MAXSEG,length,mss */
*opt++ = 4;
*(WORD*) opt = intel16 (s->max_seg);
return (4);
}
/*
* Insert TimeStamp option.
*/
static __inline int tcp_opt_timestamp (tcp_Socket *s, BYTE *opt,
DWORD ts_val, DWORD ts_echo)
{
*opt++ = TCPOPT_NOP; /* NOP,NOP,TIMESTAMP,length,TSval,TSecho */
*opt++ = TCPOPT_NOP;
*opt++ = TCPOPT_TIMESTAMP;
*opt++ = 10;
*(DWORD*) opt = intel (ts_val); opt += sizeof(ts_val);
*(DWORD*) opt = intel (ts_echo); opt += sizeof(ts_echo);
s->ts_sent = ts_val; /* remember ts_sent */
return (12);
}
#ifdef NOT_USED
/*
* Pad options to multiple of 4 bytes.
*/
static __inline int tcp_opt_padding (BYTE *opt, int len)
{
int i, pad = len % 4;
for (i = 0; i < pad; i++)
*opt++ = TCPOPT_NOP;
return (i);
}
static __inline int tcp_opt_winscale (tcp_Socket *s, BYTE *opt)
{
*opt++ = TCPOPT_WINDOW; /* option: WINDOW,length,wscale */
*opt++ = 4;
*(WORD*) opt = intel16 (s->send_wscale);
return (4);
}
static __inline int tcp_opt_sack_ok (tcp_Socket *s, BYTE *opt)
{
*opt++ = TCPOPT_SACKOK;
*opt++ = 2;
*opt++ = TCPOPT_NOP;
*opt++ = TCPOPT_NOP;
return (4);
}
static __inline int tcp_opt_sack (tcp_Socket *s, BYTE *opt,
struct SACK_list *sack)
{
int i, len = 2 + 8 * sack->num_blk;
*opt++ = TCPOPT_SACK; /* option: SACK,length,left,right,.. */
*opt++ = len;
for (i = 0; i < sack->num_blk; i++)
{
*(DWORD*) opt = intel (sack->list[i].left_edge);
opt += sizeof(DWORD);
*(DWORD*) opt = intel (sack->list[i].right_edge);
opt += sizeof(DWORD);
}
for (i = 0; i < len % 4; i++)
*opt++ = TCPOPT_NOP;
return (len + i);
}
#endif
/*
* tcp_do_options - Add TCP options to output segment
*/
static __inline int tcp_do_options (tcp_Socket *s, BYTE *opt, BOOL is_syn)
{
DWORD now = set_timeout (0);
int len = 0;
if (is_syn && !(s->locflags & LF_NOOPT))
{
len += tcp_opt_maxsegment (s, opt);
if (s->locflags & LF_REQ_TSTMP)
len += tcp_opt_timestamp (s, opt+len, now, 0UL);
#if 0
if (s->locflags & LF_REQ_SCALE)
len += tcp_opt_winscale (s, opt+len);
if (tcp_opt_sackok)
len += tcp_opt_sack_ok (s, opt+len);
#endif
}
else if (!is_syn)
{
/* We got a TS option in a previous SYN-ACK or SYN.
* Send it back unless we send a RST or disallow options.
* A Win98 host will have 0 in 's->ts_recent'
*/
if ((s->flags & tcp_FlagRST) == 0 && tcp_opt_timstmp &&
(s->locflags & (LF_RCVD_TSTMP|LF_NOOPT)) == LF_RCVD_TSTMP)
{
len += tcp_opt_timestamp (s, opt, now, s->ts_recent);
s->locflags &= ~LF_RCVD_TSTMP; /* don't echo this again */
}
}
#ifdef USE_DEBUG
assert (len == 0 || len % 4 == 0);
#endif
return (len);
}
/*
* _tcp_send - Format and send an outgoing segment.
* Several packets may be sent depending on peer's window.
*/
int _tcp_send (tcp_Socket *s, char *file, unsigned line)
{
#include <sys/packon.h>
struct tcp_pkt {
in_Header in;
tcp_Header tcp;
} *pkt;
#include <sys/packoff.h>
tcp_PseudoHeader ph;
BOOL tx_ok;
BYTE *data; /* where to copy user's data */
mac_address *dst;
in_Header *ip;
tcp_Header *tcp;
int sendtotlen = 0; /* count of data length we've sent */
int senddatalen; /* how much data in this segment */
int startdata; /* where data starts in tx-buffer */
int sendtotdata; /* total amount of data to send */
int tcp_len; /* total length of TCP segment */
int opt_len; /* total length of TCP options */
int pkt_num; /* 0..s->cwindow-1 */
int rtt;
s->recent = 0;
dst = (_pktserial ? NULL : &s->hisethaddr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -