📄 tcp.c
字号:
/*
tcp.c
*/
#include "inet.h"
#include "buf.h"
#include "clock.h"
#include "type.h"
#include "io.h"
#include "ip.h"
#include "sr.h"
#include "assert.h"
#include "tcp.h"
#include "tcp_int.h"
INIT_PANIC();
PUBLIC tcp_port_t tcp_port_table[TCP_PORT_NR];
PUBLIC tcp_fd_t tcp_fd_table[TCP_FD_NR];
PUBLIC tcp_conn_t tcp_conn_table[TCP_CONN_NR];
FORWARD void tcp_main ARGS(( tcp_port_t *port ));
FORWARD acc_t *tcp_get_data ARGS(( int fd, size_t offset,
size_t count, int for_ioctl ));
FORWARD int tcp_put_data ARGS(( int fd, size_t offset,
acc_t *data, int for_ioctl ));
FORWARD void read_ip_packets ARGS(( tcp_port_t *port ));
FORWARD int tcp_setconf ARGS(( tcp_fd_t *tcp_fd ));
FORWARD int tcp_connect ARGS(( tcp_fd_t *tcp_fd ));
FORWARD int tcp_listen ARGS(( tcp_fd_t *tcp_fd ));
FORWARD int tcp_attache ARGS(( tcp_fd_t *tcp_fd ));
FORWARD tcpport_t find_unused_port ARGS(( int fd ));
FORWARD int is_unused_port ARGS(( Tcpport_t port ));
FORWARD int reply_thr_put ARGS(( tcp_fd_t *tcp_fd, int reply,
int for_ioctl ));
FORWARD void reply_thr_get ARGS(( tcp_fd_t *tcp_fd, int reply,
int for_ioctl ));
FORWARD tcp_conn_t *find_conn_entry ARGS(( Tcpport_t locport,
ipaddr_t locaddr, Tcpport_t remport, ipaddr_t readaddr ));
FORWARD tcp_conn_t *find_empty_conn ARGS(( void ));
FORWARD void process_inc_fragm ARGS(( tcp_port_t *tcp_port,
acc_t *data ));
FORWARD tcp_conn_t *find_best_conn ARGS(( ip_hdr_t *ip_hdr,
tcp_hdr_t *tcp_hdr ));
FORWARD void close_mainuser ARGS(( tcp_conn_t *tcp_conn,
tcp_fd_t *tcp_fd ));
FORWARD int conn_right4fd ARGS(( tcp_conn_t *tcp_conn, tcp_fd_t *tcp_fd ));
FORWARD int tcp_su4connect ARGS(( tcp_fd_t *tcp_fd ));
FORWARD void tcp_buffree ARGS(( int priority, size_t reqsize ));
FORWARD void tcp_notreach ARGS(( acc_t *pack ));
FORWARD void tcp_setup_conn ARGS(( tcp_conn_t *tcp_conn ));
PUBLIC void tcp_init()
{
int i, result;
tcp_fd_t *tcp_fd;
tcp_port_t *tcp_port;
tcp_conn_t *tcp_conn;
assert (BUF_S >= sizeof(struct nwio_ipopt));
assert (BUF_S >= sizeof(struct nwio_ipconf));
assert (BUF_S >= sizeof(struct nwio_tcpconf));
assert (BUF_S >= IP_MAX_HDR_SIZE);
assert (BUF_S >= TCP_MAX_HDR_SIZE);
tcp_port_table[0].tp_minor= TCP_DEV0;
tcp_port_table[0].tp_ipdev= IP0;
for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++, tcp_fd++)
{
tcp_fd->tf_flags= TFF_EMPTY;
}
for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
tcp_fd++)
{
tcp_conn->tc_flags= TCF_EMPTY;
#if DEBUG & 256
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
}
bf_logon(tcp_buffree);
for (i=0, tcp_port= tcp_port_table; i<TCP_PORT_NR; i++,
tcp_port++)
{
tcp_port->tp_flags= TPF_EMPTY;
tcp_port->tp_state= TPS_EMPTY;
result= sr_add_minor (tcp_port->tp_minor,
tcp_port-tcp_port_table, tcp_open, tcp_close,
tcp_read, tcp_write, tcp_ioctl, tcp_cancel);
assert (result>=0);
tcp_main(tcp_port);
}
}
PRIVATE void tcp_main(tcp_port)
tcp_port_t *tcp_port;
{
int result, i;
tcp_conn_t *tcp_conn;
tcp_fd_t *tcp_fd;
switch (tcp_port->tp_state)
{
case TPS_EMPTY:
tcp_port->tp_state= TPS_SETPROTO;
#if DEBUG & 256
{ where(); printf("doing ip_open\n"); }
#endif
tcp_port->tp_ipfd= ip_open(tcp_port->tp_ipdev,
tcp_port-tcp_port_table, tcp_get_data,
tcp_put_data);
if (tcp_port->tp_ipfd < 0)
{
tcp_port->tp_state= TPS_ERROR;
printf("%s, %d: unable to open ip port\n",
__FILE__, __LINE__);
return;
}
#if DEBUG & 256
{ where(); printf("doing ip_ioctl(.., NWIOSIPOPT)\n"); }
#endif
result= ip_ioctl(tcp_port->tp_ipfd, NWIOSIPOPT);
if (result == NW_SUSPEND)
tcp_port->tp_flags |= TPF_SUSPEND;
if (result < 0)
{
#if DEBUG
{ where(); printf("ip_ioctl(..,%lx)=%d\n", NWIOSIPOPT, result); }
#endif
return;
}
if (tcp_port->tp_state != TPS_GETCONF)
return;
/* drops through */
case TPS_GETCONF:
tcp_port->tp_flags &= ~TPF_SUSPEND;
#if DEBUG & 256
{ where(); printf("doing ip_ioctl(.., NWIOGIPCONF)\n"); }
#endif
result= ip_ioctl(tcp_port->tp_ipfd, NWIOGIPCONF);
if (result == NW_SUSPEND)
tcp_port->tp_flags |= TPF_SUSPEND;
if (result < 0)
{
#if DEBUG & 256
{ where(); printf("ip_ioctl(..,%lx)=%d\n", NWIOGIPCONF, result); }
#endif
return;
}
if (tcp_port->tp_state != TPS_MAIN)
return;
/* drops through */
case TPS_MAIN:
tcp_port->tp_flags &= ~TPF_SUSPEND;
tcp_port->tp_pack= 0;
tcp_conn= &tcp_conn_table[tcp_port-tcp_port_table];
tcp_conn->tc_flags= TCF_INUSE;
#if DEBUG & 16
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
tcp_conn->tc_locport= 0;
tcp_conn->tc_locaddr= tcp_port->tp_ipaddr;
tcp_conn->tc_remport= 0;
tcp_conn->tc_remaddr= 0;
tcp_conn->tc_state= TCS_CLOSED;
#if DEBUG & 2
{ where(); tcp_write_state(tcp_conn); }
#endif
tcp_conn->tc_mainuser= 0;
tcp_conn->tc_readuser= 0;
tcp_conn->tc_writeuser= 0;
tcp_conn->tc_connuser= 0;
#if DEBUG & 256
{ where(); printf("tcp_conn_table[%d].tc_connuser= 0x%x\n", tcp_conn-
tcp_conn_table, tcp_conn->tc_connuser); }
#endif
tcp_conn->tc_orglisten= FALSE;
tcp_conn->tc_senddis= 0;
tcp_conn->tc_ISS= 0;
tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS;
tcp_conn->tc_SND_UP= tcp_conn->tc_ISS;
tcp_conn->tc_SND_WL2= tcp_conn->tc_ISS;
tcp_conn->tc_IRS= 0;
tcp_conn->tc_SND_WL1= tcp_conn->tc_IRS;
tcp_conn->tc_RCV_LO= tcp_conn->tc_IRS;
tcp_conn->tc_RCV_NXT= tcp_conn->tc_IRS;
tcp_conn->tc_RCV_HI= tcp_conn->tc_IRS;
tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
tcp_conn->tc_port= tcp_port;
tcp_conn->tc_rcvd_data= 0;
tcp_conn->tc_rcv_queue= 0;
tcp_conn->tc_send_data= 0;
tcp_conn->tc_remipopt= 0;
tcp_conn->tc_remtcpopt= 0;
tcp_conn->tc_frag2send= 0;
tcp_conn->tc_tos= TCP_DEF_TOS;
tcp_conn->tc_ttl= IP_MAX_TTL;
tcp_conn->tc_rcv_wnd= TCP_MAX_WND_SIZE;
tcp_conn->tc_urg_wnd= TCP_DEF_URG_WND;
tcp_conn->tc_max_no_retrans= TCP_DEF_MAX_NO_RETRANS;
tcp_conn->tc_0wnd_to= 0;
tcp_conn->tc_rtt= TCP_DEF_RTT;
tcp_conn->tc_ett= 0;
tcp_conn->tc_mss= TCP_DEF_MSS;
tcp_conn->tc_error= NW_OK;
tcp_conn->tc_snd_wnd= TCP_MAX_WND_SIZE;
for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++,
tcp_fd++)
{
if (!(tcp_fd->tf_flags & TFF_INUSE))
continue;
if (tcp_fd->tf_port != tcp_port)
continue;
if (tcp_fd->tf_flags & TFF_IOC_INIT_SP)
{
tcp_fd->tf_flags &= ~TFF_IOC_INIT_SP;
#if DEBUG & 256
{ where(); printf("restarting tcp_ioctl\n"); }
#endif
tcp_ioctl(i, tcp_fd->tf_ioreq);
}
}
read_ip_packets(tcp_port);
return;
default:
ip_panic(( "unknown state" ));
break;
}
}
PRIVATE acc_t *tcp_get_data (port, offset, count, for_ioctl)
int port;
size_t offset;
size_t count;
int for_ioctl;
{
tcp_port_t *tcp_port;
int result;
tcp_port= &tcp_port_table[port];
switch (tcp_port->tp_state)
{
case TPS_SETPROTO:
if (!count)
{
result= (int)offset;
if (result<0)
{
tcp_port->tp_state= TPS_ERROR;
break;
}
tcp_port->tp_state= TPS_GETCONF;
if (tcp_port->tp_flags & TPF_SUSPEND)
tcp_main(tcp_port);
return NW_OK;
}
assert (!offset);
assert (count == sizeof(struct nwio_ipopt));
{
struct nwio_ipopt *ipopt;
acc_t *acc;
acc= bf_memreq(sizeof(*ipopt));
ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
ipopt->nwio_flags= NWIO_COPY |
NWIO_EN_LOC | NWIO_DI_BROAD |
NWIO_REMANY | NWIO_PROTOSPEC |
NWIO_HDR_O_ANY | NWIO_RWDATALL;
ipopt->nwio_proto= IPPROTO_TCP;
return acc;
}
case TPS_MAIN:
assert(tcp_port->tp_flags & TPF_WRITE_IP);
if (!count)
{
result= (int)offset;
#if DEBUG & 256
{ where(); printf("tcp_get_data: got reply: %d\n", result); }
#endif
if (result<0)
{
if (result == EDSTNOTRCH)
{
tcp_notreach(tcp_port->tp_pack);
}
else
{
ip_warning((
"ip_write failed with error: %d\n",
result ));
}
}
assert (tcp_port->tp_pack);
bf_afree (tcp_port->tp_pack);
tcp_port->tp_pack= 0;
if (tcp_port->tp_flags & TPF_WRITE_SP)
{
tcp_port->tp_flags &= ~(TPF_WRITE_SP|
TPF_WRITE_IP);
if (tcp_port->tp_flags & TPF_MORE2WRITE)
{
#if DEBUG & 256
{ where(); printf("calling tcp_restart_write_port(&tcp_port_table[%d])\n",
tcp_port - tcp_port_table); }
#endif
tcp_restart_write_port(
tcp_port);
}
}
else
tcp_port->tp_flags &= ~TPF_WRITE_IP;
}
else
{
#if DEBUG & 256
{ where(); printf("suplying data, count= %d, offset= %d, bufsize= %d\n",
count, offset, bf_bufsize(tcp_port->tp_pack)); }
#endif
return bf_cut (tcp_port->tp_pack, offset,
count);
}
break;
default:
printf("tcp_get_data(%d, 0x%x, 0x%x) called but tp_state= 0x%x\n",
port, offset, count, tcp_port->tp_state);
break;
}
return NW_OK;
}
PRIVATE int tcp_put_data (fd, offset, data, for_ioctl)
int fd;
size_t offset;
acc_t *data;
int for_ioctl;
{
tcp_port_t *tcp_port;
int result;
tcp_port= &tcp_port_table[fd];
switch (tcp_port->tp_state)
{
case TPS_GETCONF:
if (!data)
{
result= (int)offset;
if (result<0)
{
tcp_port->tp_state= TPS_ERROR;
return NW_OK;
}
tcp_port->tp_state= TPS_MAIN;
#if DEBUG & 256
{ where(); printf("get GETCONF reply\n"); }
#endif
if (tcp_port->tp_flags & TPF_SUSPEND)
tcp_main(tcp_port);
}
else
{
struct nwio_ipconf *ipconf;
data= bf_packIffLess(data, sizeof(*ipconf));
ipconf= (struct nwio_ipconf *)ptr2acc_data(data);
assert (ipconf->nwic_flags & NWIC_IPADDR_SET);
tcp_port->tp_ipaddr= ipconf->nwic_ipaddr;
bf_afree(data);
}
break;
case TPS_MAIN:
assert(tcp_port->tp_flags & TPF_READ_IP);
if (!data)
{
result= (int)offset;
if (result<0)
#if DEBUG
{ where(); printf("tcp_put_data got error %d (ignored)\n", result); }
#else
ip_panic(( "ip_read() failed" ));
#endif
if (tcp_port->tp_flags & TPF_READ_SP)
{
tcp_port->tp_flags &= ~(TPF_READ_SP|
TPF_READ_IP);
read_ip_packets(tcp_port);
}
else
tcp_port->tp_flags &= ~TPF_READ_IP;
}
else
{
assert(!offset); /* this isn't a valid assertion but ip sends
* only whole datagrams up */
#if DEBUG & 256
{ where(); printf("got data from ip\n"); }
#endif
process_inc_fragm(tcp_port, data);
}
break;
default:
printf("tcp_put_data(%d, 0x%x, 0x%x) called but tp_state= 0x%x\n",
fd, offset, data, tcp_port->tp_state);
break;
}
return NW_OK;
}
PUBLIC int tcp_open (port, srfd, get_userdata, put_userdata)
int port;
int srfd;
get_userdata_t get_userdata;
put_userdata_t put_userdata;
{
int i;
tcp_fd_t *tcp_fd;
for (i=0; i<TCP_FD_NR && (tcp_fd_table[i].tf_flags & TFF_INUSE);
i++);
if (i>=TCP_FD_NR)
{
#if DEBUG
{ where(); printf("out of fds\n"); }
#endif
return EOUTOFBUFS;
}
tcp_fd= &tcp_fd_table[i];
tcp_fd->tf_flags= TFF_INUSE;
tcp_fd->tf_flags |= TFF_PUSH_DATA; /* XXX */
tcp_fd->tf_port= &tcp_port_table[port];
tcp_fd->tf_srfd= srfd;
tcp_fd->tf_tcpconf.nwtc_flags= TCP_DEF_OPT;
tcp_fd->tf_tcpconf.nwtc_remaddr= 0;
tcp_fd->tf_tcpconf.nwtc_remport= 0;
tcp_fd->tf_get_userdata= get_userdata;
tcp_fd->tf_put_userdata= put_userdata;
tcp_fd->tf_conn= 0;
return i;
}
PUBLIC int tcp_ioctl (fd, req)
int fd;
int req;
{
tcp_fd_t *tcp_fd;
tcp_port_t *tcp_port;
tcp_conn_t *tcp_conn;
nwio_tcpconf_t *tcp_conf;
acc_t *conf_acc;
int type;
int result;
#if DEBUG & 256
{ where(); printf("tcp_ioctl called\n"); }
#endif
tcp_fd= &tcp_fd_table[fd];
type= req & IOCTYPE_MASK;
assert (tcp_fd->tf_flags & TFF_INUSE);
tcp_port= tcp_fd->tf_port;
tcp_fd->tf_flags |= TFF_IOCTL_IP;
tcp_fd->tf_ioreq= req;
if (tcp_port->tp_state != TPS_MAIN)
{
tcp_fd->tf_flags |= TFF_IOC_INIT_SP;
return NW_SUSPEND;
}
switch (type)
{
case NWIOSTCPCONF & IOCTYPE_MASK:
if (req != NWIOSTCPCONF)
{
#if DEBUG
{ where(); printf("0x%x: bad ioctl\n", req); }
#endif
tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
reply_thr_get (tcp_fd, EBADIOCTL, TRUE);
result= NW_OK;
break;
}
if (tcp_fd->tf_flags & TFF_CONNECTED)
{
tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
reply_thr_get (tcp_fd, EISCONN, TRUE);
result= NW_OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -