⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.c

📁 minux的源代码,一个非常小的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
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 + -