pctcp.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 2,251 行 · 第 1/4 页
C
2,251 行
pkt = (struct tcp_pkt*) _eth_formatpacket (dst, IP_TYPE);
ip = &pkt->in;
tcp = &pkt->tcp;
data = (BYTE*) (tcp+1);
if (s->karn_count == 2) /* doing slow-start */
{
sendtotdata = min (s->datalen, s->window);
startdata = 0;
}
else
{
/* Morten Terstrup <MorTer@dk-online.dk> found this signed bug
*/
int size = min (s->datalen, s->window);
sendtotdata = size - s->unacked;
if (sendtotdata < 0)
sendtotdata = 0;
startdata = s->unacked;
}
/* step through our packets
*/
for (pkt_num = 0; pkt_num < s->cwindow; pkt_num++)
{
/* make tcp header
*/
tcp->srcPort = intel16 (s->myport);
tcp->dstPort = intel16 (s->hisport);
tcp->seqnum = intel (s->seqnum + startdata); /* unacked - no longer sendtotlen */
tcp->acknum = intel (s->acknum);
tcp->window = intel16 (s->maxrdatalen - s->rdatalen);
tcp->flags = s->flags;
tcp->unused = 0;
tcp->checksum = 0;
tcp->urgent = 0;
/* Insert any TCP options after header
*/
if (pkt_num == 0 && (s->flags & (tcp_FlagSYN|tcp_FlagACK)) == tcp_FlagSYN)
{
opt_len = tcp_do_options (s, data, TRUE);
senddatalen = 0; /* no data, only options */
}
else
{
int data_free;
opt_len = tcp_do_options (s, data, FALSE);
if ((data_free = s->max_seg - opt_len) < 0)
data_free = 0;
senddatalen = min (sendtotdata, data_free);
}
tcp_len = sizeof(*tcp) + opt_len;
data += opt_len;
tcp->offset = tcp_len/4;
if (senddatalen > 0) /* non-SYN packets with data */
{
tcp_len += senddatalen;
if (s->queuelen)
memcpy (data, s->queue+startdata, senddatalen);
else memcpy (data, s->data +startdata, senddatalen);
}
if (s->locflags & LF_NOPUSH)
tcp->flags &= ~tcp_FlagPUSH;
/* make tcp header check-sum
*/
memset (&ph, 0, sizeof(ph));
ph.src = intel (s->myaddr);
ph.dst = intel (s->hisaddr);
ph.protocol = TCP_PROTO;
ph.length = intel16 (tcp_len);
ph.checksum = checksum (tcp, tcp_len);
tcp->checksum = ~checksum (&ph, sizeof(ph));
tx_ok = _ip_output (ip, ph.src, ph.dst, TCP_PROTO,
s->ttl, s->tos, 0, tcp_len, s, file, line) != 0;
if (!tx_ok)
{
TCP_SENDSOON (s);
return (-1);
}
/* do next packet
*/
if (senddatalen > 0)
{
sendtotlen += senddatalen;
startdata += senddatalen;
sendtotdata -= senddatalen;
}
if (sendtotdata <= 0)
break;
}
s->unacked = startdata;
#if defined(USE_DEBUG)
if (debug_on > 1)
(*_printf)(" Sent %u (win %u) bytes in %u (cwin %u) packets with "
"(%u) unacked SEQ %lu line %u\r\n",
sendtotlen, s->window, pkt_num, s->cwindow,
s->unacked, s->seqnum, line);
#endif
s->vj_last = 0UL;
if (s->karn_count == 2)
{
if (s->rto)
s->rto = (s->rto * 3) / 2; /* increase by 50% */
else s->rto = 2*tcp_RTO_ADD; /* !!was 4 tick */
}
else
{
/* vj_last nonzero if we expect an immediate response
*/
if (s->unhappy || s->datalen)
s->vj_last = set_timeout (0);
s->karn_count = 0;
}
rtt = s->rto + tcp_RTO_ADD;
s->rtt_time = set_timeout (rtt);
if (sendtotlen > 0)
s->rtt_lasttran = s->rtt_time;
return (sendtotlen);
}
/*
* Force the peer to send us a segment by sending a keep-alive packet:
* <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
*/
int sock_keepalive (sock_type *s)
{
tcp_Socket *tcp;
DWORD ack, seq;
BYTE kc;
int datalen;
if (s->tcp.ip_type != TCP_PROTO)
return (0);
tcp = &s->tcp;
ack = tcp->acknum;
seq = tcp->seqnum;
kc = tcp->karn_count;
datalen = tcp->datalen;
tcp->acknum = tcp->seqnum;
tcp->seqnum = tcp->unacked - 1;
tcp->flags = tcp_FlagACK;
tcp->karn_count = 2;
tcp->datalen = 0;
(void) TCP_SEND (tcp);
tcp->acknum = ack;
tcp->seqnum = seq;
tcp->karn_count = kc;
tcp->datalen = datalen;
STAT (tcpstats.tcps_keepprobe++);
STAT (tcpstats.tcps_keeptimeo++);
return (1);
}
#endif /* !USE_UDP_ONLY */
/*
* sock_mode - set binary or ascii - affects sock_gets, sock_dataready
* - set udp checksums
*/
WORD sock_mode (sock_type *s, WORD mode)
{
if (s->tcp.ip_type == TCP_PROTO || s->tcp.ip_type == UDP_PROTO)
{
s->tcp.sockmode = (s->tcp.sockmode & 0xFFFC) | mode;
return (s->tcp.sockmode);
}
return (0);
}
/*
* sock_yield - enable user defined yield function
*/
int sock_yield (tcp_Socket *s, void (*fn)())
{
if (s)
s->usr_yield = fn;
else system_yield = fn;
return (0);
}
void sock_abort (sock_type *s)
{
switch (s->tcp.ip_type)
{
#if !defined(USE_UDP_ONLY)
case TCP_PROTO:
tcp_abort (&s->tcp);
break;
#endif
case UDP_PROTO:
udp_close (&s->udp);
break;
case IP_TYPE:
s->raw.ip_type = 0;
s->raw.used = 0;
break;
}
}
#if defined(USE_BSD_FUNC)
/*
* Read data from a raw-socket. Don't copy IP-header to buf.
*/
static int raw_read (raw_Socket *raw, BYTE *buf, int maxlen)
{
int len = 0;
if (raw->used)
{
int hlen = in_GetHdrLen (&raw->ip);
BYTE *data = (BYTE*)&raw->ip + hlen;
len = intel16 (raw->ip.length) - hlen;
len = min (len, maxlen);
memcpy (buf, data, len);
raw->used = 0;
}
return (len);
}
#endif
/*
* sock_read - read a socket with maximum 'maxlen' bytes
* - busywaits until 'buf' is full (and call 's->usr_yield')
* - returns count ( <= maxlen) also when connection gets closed
*/
int sock_read (sock_type *s, BYTE *buf, int maxlen)
{
int count = 0;
do
{
int len = 0;
int raw = 0;
switch (s->udp.ip_type)
{
#if !defined(USE_UDP_ONLY)
case TCP_PROTO:
len = tcp_read (&s->tcp, buf, maxlen);
break;
#endif
case UDP_PROTO:
len = udp_read (&s->udp, buf, maxlen);
break;
#if defined(USE_BSD_FUNC)
case IP_TYPE:
raw = TRUE;
len = raw_read (&s->raw, buf, maxlen);
break;
#endif
}
if (len < 1)
{
if (!tcp_tick(s))
return (count);
}
else
{
count += len;
buf += len;
maxlen -= len;
}
if (maxlen > 0 && !raw && s->tcp.usr_yield) /* yield only when room */
(*s->tcp.usr_yield)(); /* 99.07.01 EE */
}
while (maxlen);
return (count);
}
/*
* sock_fastread - read a socket with maximum 'len' bytes
* - does not busywait until buffer is full
*/
int sock_fastread (sock_type *s, BYTE *buf, int len)
{
if (s->udp.ip_type == UDP_PROTO)
return udp_read (&s->udp, buf, len);
#if !defined(USE_UDP_ONLY)
if (s->tcp.ip_type == TCP_PROTO || s->tcp.rdatalen > 0)
return tcp_read (&s->tcp, buf, len);
#endif
#if defined(USE_BSD_FUNC)
if (s->raw.ip_type == IP_TYPE)
return raw_read (&s->raw, buf, len);
#endif
return (-1);
}
/*
* sock_write - writes data and returns length written
* - send with PUSH-bit (flush data)
* - repeatedly calls s->usr_yield
*/
int sock_write (sock_type *s, const BYTE *data, int len)
{
int chunk = len;
int written = 0;
while (chunk > 0)
{
switch (s->udp.ip_type)
{
#if !defined(USE_UDP_ONLY)
case TCP_PROTO:
s->tcp.flags |= tcp_FlagPUSH;
written = tcp_write (&s->tcp, data, chunk);
break;
#endif
case UDP_PROTO:
chunk = min (mtu - sizeof(in_Header) - sizeof(udp_Header), chunk);
written = udp_write (&s->udp, data, chunk);
break;
#if defined(USE_BSD_FUNC)
case IP_TYPE:
return (0); /* not supported yet */
#endif
default: /* EE 99.06.14 */
return (0);
}
if (written < 0)
{
s->udp.err_msg = _LANG("Tx Error");
return (0);
}
data += written;
chunk -= written;
if (s->udp.usr_yield)
(*s->udp.usr_yield)();
if (!tcp_tick(s))
return (0);
}
return (len);
}
/*
* sock_fastwrite
*
* NOTE: for UDP, assumes data fits in one datagram, else only the first
* fragment will be sent! Because MTU is used for splits,
* by default the max data size is MTU-(20+sizeof(udp_Header)) = 548
* for a non-fragged datagram.
*/
int sock_fastwrite (sock_type *s, const BYTE *data, int len)
{
switch (s->udp.ip_type)
{
case UDP_PROTO:
len = min (mtu - sizeof(in_Header) - sizeof(udp_Header), len);
len = udp_write (&s->udp, data, len);
return (len < 0 ? 0 : len);
#if !defined(USE_UDP_ONLY)
case TCP_PROTO:
len = tcp_write (&s->tcp, data, len);
return (len < 0 ? 0 : len);
#endif
}
return (0);
}
int sock_enqueue (sock_type *s, const BYTE *data, int len)
{
if (len <= 0)
return (0);
if (s->udp.ip_type == UDP_PROTO)
{
int written = 0;
int total = 0;
do
{
len = min (mtu - sizeof(in_Header) - sizeof(udp_Header), len);
written = udp_write (&s->udp, data, len);
if (written < 0)
{
s->udp.err_msg = _LANG("Tx Error");
break;
}
data += written;
len -= written;
total += written;
}
while (len > 0);
return (total);
}
#if !defined(USE_UDP_ONLY)
if (s->tcp.ip_type == TCP_PROTO)
{
s->tcp.queue = data;
s->tcp.queuelen = len;
s->tcp.datalen = len;
return TCP_SEND (&s->tcp);
}
#endif
return (0);
}
#if !defined(USE_UDP_ONLY)
void sock_noflush (sock_type *s)
{
if (s->tcp.ip_type == TCP_PROTO)
{
s->tcp.flags &= ~tcp_FlagPUSH;
s->tcp.sockmode |= TCP_LOCAL;
}
}
/*
* sock_flush - Send pending TCP data
*/
void sock_flush (sock_type *s)
{
if (s->tcp.ip_type == TCP_PROTO)
{
tcp_Socket *tcp = &s->tcp;
tcp->sockmode &= ~TCP_LOCAL;
if (tcp->datalen > 0)
{
tcp->flags |= tcp_FlagPUSH;
if (s->tcp.unacked == 0) /* !! S. Lawson - only if data not moving */
(void) TCP_SEND (tcp);
}
}
}
/*
* sock_flushnext - cause next transmission to have a flush
*/
void sock_flushnext (sock_type *s)
{
if (s->tcp.ip_type == TCP_PROTO)
{
s->tcp.flags |= tcp_FlagPUSH;
s->tcp.sockmode &= ~TCP_LOCAL;
}
}
#endif /* !USE_UDP_ONLY */
int sock_close (sock_type *s)
{
switch (s->tcp.ip_type)
{
case UDP_PROTO:
udp_close (&s->udp);
break;
#if !defined(USE_UDP_ONLY)
case TCP_PROTO:
_tcp_close (&s->tcp);
(void) tcp_tick (s);
break;
#endif
}
return (0);
}
#if !defined(USE_UDP_ONLY)
/*
* Round trip timing cache routines.
* These functions implement a very simple system for keeping track of
* network performance for future use in new connections.
* The emphasis here is on speed of update (rather than optimum cache
* hit ratio) since tcp_rtt_add() is called every time a TCP connection
* updates its round trip estimate. Note: 'rto' is either in ticks or
* milli-sec depending on if PC has an 8254 Time chip.
*
* These routines are modified versions from KA9Q by Phil Karn.
*/
static struct tcp_rtt rtt_cache [RTTCACHE];
static void tcp_rtt_add (tcp_Socket *s, UINT rto)
{
struct tcp_rtt *rtt;
DWORD addr = s->hisaddr;
if (~addr & ~sin_mask) /* 0.0.0.0 or broadcast addresses? */
return;
rtt = &rtt_cache [(WORD)addr % RTTCACHE];
/* Cache-slot is vacant or we're updating previous RTO
* for same peer
*/
if (!rtt->ip || rtt->ip == addr)
{
rtt->ip = addr;
rtt->rto = rto;
STAT (tcpstats.tcps_cachedrtt++);
}
}
static UINT tcp_rtt_get (tcp_Socket *s)
{
struct tcp_rtt *rtt = &rtt_cache [(WORD)s->hisaddr % RTTCACHE];
if (s->hisaddr && rtt->ip == s->hisaddr && rtt->rto > 0)
{
#if defined(USE_DEBUG) && !defined(_MSC_VER) /* MSC6 crashes below */
char buf[20];
dbug_write_raw ("\r\nRTT-cache: host ");
dbug_write_raw (_inet_ntoa(buf, rtt->ip));
dbug_write_raw (": ");
dbug_write_raw (time_str(rtt->rto));
dbug_write_raw ("s\r\n\r\n");
#endif
STAT (tcpstats.tcps_usedrtt++);
return (rtt->rto);
}
return (0);
}
static void tcp_rtt_clr (tcp_Socket *s)
{
struct tcp_rtt *rtt = &rtt_cache [(WORD)s->hisaddr % RTTCACHE];
if (s->hisaddr && rtt->ip == s->hisaddr)
{
rtt->rto = 0;
rtt->ip = 0;
}
}
#endif /* !USE_UDP_ONLY */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?