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

📄 tcp.c

📁 minux的源代码,一个非常小的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
			break;
		}
		result= tcp_setconf(tcp_fd);
		break;
	case NWIOGTCPCONF & IOCTYPE_MASK:
		if (req != NWIOGTCPCONF)
		{
			tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
			reply_thr_put (tcp_fd, EBADIOCTL, TRUE);
			result= NW_OK;
			break;
		}
		conf_acc= bf_memreq(sizeof(*tcp_conf));
assert (conf_acc->acc_length == sizeof(*tcp_conf));
		tcp_conf= (nwio_tcpconf_t *)ptr2acc_data(conf_acc);

		*tcp_conf= tcp_fd->tf_tcpconf;
		if (tcp_fd->tf_flags & TFF_CONNECTED)
		{
			tcp_conn= tcp_fd->tf_conn;
			tcp_conf->nwtc_locport= tcp_conn->tc_locport;
			tcp_conf->nwtc_remaddr= tcp_conn->tc_remaddr;
			tcp_conf->nwtc_remport= tcp_conn->tc_remport;
		}
		tcp_conf->nwtc_locaddr= tcp_fd->tf_port->tp_ipaddr;
		result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
			0, conf_acc, TRUE);
		tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
		reply_thr_put(tcp_fd, result, TRUE);
		result= NW_OK;
		break;
	case NWIOTCPCONN & IOCTYPE_MASK:
		if (req != NWIOTCPCONN)
		{
			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;
			break;
		}
		result= tcp_connect(tcp_fd);
		break;
	case NWIOTCPLISTEN & IOCTYPE_MASK:
		if (req != NWIOTCPLISTEN)
		{
			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;
			break;
		}
		result= tcp_listen(tcp_fd);
#if DEBUG & 256
 { where(); printf("tcp_listen= %d\n", result); }
#endif
		break;
#if 0
	case NWIOTCPATTACH & IOCTYPE_MASK:
		if (req != NWIOTCPATTACH)
		{
			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;
			break;
		}
		result= tcp_attache(tcp_fd);
		break;
#endif
	case NWIOTCPSHUTDOWN & IOCTYPE_MASK:
		if (req != NWIOTCPSHUTDOWN)
		{
			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, ENOTCONN, TRUE);
			result= NW_OK;
			break;
		}
		tcp_fd->tf_flags |= TFF_IOCTL_IP;
		tcp_fd->tf_ioreq= req;
		tcp_conn= tcp_fd->tf_conn;
		if (tcp_conn->tc_writeuser)
			return NW_SUSPEND;

		tcp_conn->tc_writeuser= tcp_fd;
		tcp_restart_fd_write (tcp_conn);
		if (!(tcp_fd->tf_flags & TFF_IOCTL_IP))
			return NW_OK;
		else
			return NW_SUSPEND;
		break;
	default:
		tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
		reply_thr_get(tcp_fd, EBADIOCTL, TRUE);
		result= NW_OK;
		break;
	}
	return result;
}

PRIVATE int tcp_setconf(tcp_fd)
tcp_fd_t *tcp_fd;
{
	nwio_tcpconf_t *tcpconf;
	nwio_tcpconf_t oldconf, newconf;
	acc_t *data;
	int result;
	tcpport_t port;
	tcp_fd_t *fd_ptr;
	unsigned int new_en_flags, new_di_flags,
		old_en_flags, old_di_flags, all_flags, flags;
	int i;

	data= (*tcp_fd->tf_get_userdata)
		(tcp_fd->tf_srfd, 0,
		sizeof(nwio_tcpconf_t), TRUE);

	if (!data)
		return EFAULT;

	data= bf_packIffLess(data, sizeof(nwio_tcpconf_t));
assert (data->acc_length == sizeof(nwio_tcpconf_t));

	tcpconf= (nwio_tcpconf_t *)ptr2acc_data(data);
	oldconf= tcp_fd->tf_tcpconf;
	newconf= *tcpconf;

	old_en_flags= oldconf.nwtc_flags & 0xffff;
	old_di_flags= (oldconf.nwtc_flags >> 16) &
		0xffff;
	new_en_flags= newconf.nwtc_flags & 0xffff;
	new_di_flags= (newconf.nwtc_flags >> 16) &
		0xffff;
	if (new_en_flags & new_di_flags)
	{
#if DEBUG
 { where(); printf("bad ioctl\n"); }
#endif
		tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
		reply_thr_get(tcp_fd, EBADMODE, TRUE);
		return NW_OK;
	}

	/* NWTC_ACC_MASK */
	if (new_di_flags & NWTC_ACC_MASK)
	{
#if DEBUG
 { where(); printf("bad ioctl\n"); }
#endif
		tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
		reply_thr_get(tcp_fd, EBADMODE, TRUE);
		return NW_OK;
		/* access modes can't be disabled */
	}

	if (!(new_en_flags & NWTC_ACC_MASK))
		new_en_flags |= (old_en_flags & NWTC_ACC_MASK);
	
	/* NWTC_LOCPORT_MASK */
	if (new_di_flags & NWTC_LOCPORT_MASK)
	{
#if DEBUG
 { where(); printf("bad ioctl\n"); }
#endif
		tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
		reply_thr_get(tcp_fd, EBADMODE, TRUE);
		return NW_OK;
		/* the loc ports can't be disabled */
	}
	if (!(new_en_flags & NWTC_LOCPORT_MASK))
	{
		new_en_flags |= (old_en_flags &
			NWTC_LOCPORT_MASK);
#if DEBUG
 { where(); printf("locport= old locport (=%u)\n",
	ntohs(newconf.nwtc_locport)); }
#endif
		newconf.nwtc_locport= oldconf.nwtc_locport;
	}
	else if ((new_en_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL)
	{
		newconf.nwtc_locport= find_unused_port(tcp_fd-
			tcp_fd_table);
#if DEBUG & 256
 { where(); printf("locport selected (=%u)\n",
	ntohs(newconf.nwtc_locport)); }
#endif
	}
	else if ((new_en_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET)
	{
#if DEBUG & 256
 { where(); printf("locport set (=%u)\n",
   ntohs(newconf.nwtc_locport)); }
#endif
		if (!newconf.nwtc_locport)
		{
#if DEBUG
 { where(); printf("bad ioctl\n"); }
#endif
			tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
			reply_thr_get(tcp_fd, EBADMODE, TRUE);
			return NW_OK;
		}
	}
	
	/* NWTC_REMADDR_MASK */
	if (!((new_en_flags | new_di_flags) &
		NWTC_REMADDR_MASK))
	{
		new_en_flags |= (old_en_flags &
			NWTC_REMADDR_MASK);
		new_di_flags |= (old_di_flags &
			NWTC_REMADDR_MASK);
		newconf.nwtc_remaddr= oldconf.nwtc_remaddr;
	}
	else if (new_en_flags & NWTC_SET_RA)
	{
		if (!newconf.nwtc_remaddr)
		{
#if DEBUG
 { where(); printf("bad ioctl\n"); }
#endif
			tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
			reply_thr_get(tcp_fd, EBADMODE, TRUE);
			return NW_OK;
		}
	}
	else
	{
assert (new_di_flags & NWTC_REMADDR_MASK);
		newconf.nwtc_remaddr= 0;
	}

	/* NWTC_REMPORT_MASK */
	if (!((new_en_flags | new_di_flags) & NWTC_REMPORT_MASK))
	{
		new_en_flags |= (old_en_flags &
			NWTC_REMPORT_MASK);
		new_di_flags |= (old_di_flags &
			NWTC_REMPORT_MASK);
		newconf.nwtc_remport=
			oldconf.nwtc_remport;
	}
	else if (new_en_flags & NWTC_SET_RP)
	{
		if (!newconf.nwtc_remport)
		{
#if DEBUG
 { where(); printf("bad ioctl\n"); }
#endif
			tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
			reply_thr_get(tcp_fd, EBADMODE, TRUE);
			return NW_OK;
		}
	}
	else
	{
assert (new_di_flags & NWTC_REMPORT_MASK);
		newconf.nwtc_remport= 0;
	}

	newconf.nwtc_flags= ((unsigned long)new_di_flags
		<< 16) | new_en_flags;
	all_flags= new_en_flags | new_di_flags;

	/* Let's check the access modes */
	if ((all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL ||
		(all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET)
	{
		for (i=0, fd_ptr= tcp_fd_table; i<TCP_FD_NR; i++, fd_ptr++)
		{
			if (fd_ptr == tcp_fd)
				continue;
			if (!(fd_ptr->tf_flags & TFF_INUSE))
				continue;
			flags= fd_ptr->tf_tcpconf.nwtc_flags;
			if ((flags & NWTC_LOCPORT_MASK) != NWTC_LP_SEL &&
				(flags &  NWTC_LOCPORT_MASK) != NWTC_LP_SET)
				continue;
			if (fd_ptr->tf_tcpconf.nwtc_locport !=
				newconf.nwtc_locport)
				continue;
			if ((flags & NWTC_ACC_MASK) != (all_flags  &
				NWTC_ACC_MASK))
			{
				tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
				reply_thr_get(tcp_fd, EADDRINUSE, TRUE);
				return NW_OK;
			}
		}
	}
				
	tcp_fd->tf_tcpconf= newconf;

	if ((all_flags & NWTC_ACC_MASK) &&
		((all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET ||
		(all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL) &&
		(all_flags & NWTC_REMADDR_MASK) &&
		(all_flags & NWTC_REMPORT_MASK))
		tcp_fd->tf_flags |= TFF_OPTSET;
	else
	{
#if DEBUG
 { where();
   if (!(all_flags & NWTC_ACC_MASK)) printf("NWTC_ACC_MASK not set ");
   if (!(all_flags & (NWTC_LP_SET|NWTC_LP_SEL)))
    printf("local port not set ");
   if (!(all_flags & NWTC_REMADDR_MASK))
    printf("NWTC_REMADDR_MASK not set ");
   if (!(all_flags & NWTC_REMPORT_MASK))
    printf("NWTC_REMPORT_MASK not set "); }
#endif
		tcp_fd->tf_flags &= ~TFF_OPTSET;
	}
	bf_afree(data);
	tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
	reply_thr_get(tcp_fd, NW_OK, TRUE);
	return NW_OK;
}


PRIVATE tcpport_t find_unused_port(fd)
int fd;
{
	tcpport_t port, nw_port;

	for (port= 0x8000; port < 0xffff-TCP_FD_NR; port+= TCP_FD_NR)
	{
		nw_port= htons(port);
		if (is_unused_port(nw_port))
			return nw_port;
	}
	for (port= 0x8000; port < 0xffff; port++)
	{
		nw_port= htons(port);
		if (is_unused_port(nw_port))
			return nw_port;
	}
	ip_panic(( "unable to find unused port (shouldn't occur)" ));
	return 0;
}

PRIVATE int is_unused_port(port)
tcpport_t port;
{
	int i;
	tcp_fd_t *tcp_fd;
	tcp_conn_t *tcp_conn;

	for (i= 0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++,
		tcp_fd++)
	{
		if (!(tcp_fd->tf_flags & TFF_OPTSET))
			continue;
		if (tcp_fd->tf_tcpconf.nwtc_locport == port)
			return FALSE;
	}
	for (i= TCP_PORT_NR, tcp_conn= tcp_conn_table+i;
		i<TCP_CONN_NR; i++, tcp_conn++)
		/* the first TCP_PORT_NR ports are special */
	{
		if (!(tcp_conn->tc_flags & TCF_INUSE))
			continue;
		if (tcp_conn->tc_locport == port)
			return FALSE;
	}
	return TRUE;
}

PRIVATE int reply_thr_put(tcp_fd, reply, for_ioctl)
tcp_fd_t *tcp_fd;
int reply;
int for_ioctl;
{
#if DEBUG & 256
 { where(); printf("reply_thr_put(..) called\n"); }
#endif
#if DEBUG & 256
 { where(); printf("calling 0x%x\n", tcp_fd->tf_put_userdata); }
#endif
assert (tcp_fd);
	return (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd, reply,
		(acc_t *)0, for_ioctl);
}

PRIVATE void reply_thr_get(tcp_fd, reply, for_ioctl)
tcp_fd_t *tcp_fd;
int reply;
int for_ioctl;
{
	acc_t *result;
#if DEBUG & 256
 { where(); printf("reply_thr_get(..) called\n"); }
#endif
	result= (*tcp_fd->tf_get_userdata)(tcp_fd->tf_srfd, reply,
		(size_t)0, for_ioctl);
	assert (!result);
}

PUBLIC int tcp_su4listen(tcp_fd)
tcp_fd_t *tcp_fd;
{
	tcp_conn_t *tcp_conn;
	acc_t *tmp_acc;

	tcp_conn= tcp_fd->tf_conn;

	tcp_conn->tc_locport= tcp_fd->tf_tcpconf.nwtc_locport;
	tcp_conn->tc_locaddr= tcp_fd->tf_port->tp_ipaddr;
	if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP)
		tcp_conn->tc_remport= tcp_fd->tf_tcpconf.nwtc_remport;
	else
		tcp_conn->tc_remport= 0;
	if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA)
		tcp_conn->tc_remaddr= tcp_fd->tf_tcpconf.nwtc_remaddr;
	else
		tcp_conn->tc_remaddr= 0;

	tcp_setup_conn(tcp_conn);
	tcp_conn->tc_port= tcp_fd->tf_port;
	tcp_conn->tc_mainuser= tcp_fd;
	tcp_conn->tc_connuser= tcp_fd;
	tcp_conn->tc_orglisten= TRUE;
	tcp_conn->tc_state= TCS_LISTEN;
#if DEBUG & 2
 { where(); tcp_write_state(tcp_conn); }
#endif
	return NW_SUSPEND;
}

/*
find_empty_conn

This function returns a connection that is not inuse.
This includes connections that are never used, and connection without a
user that are not used for a while.
*/

PRIVATE tcp_conn_t *find_empty_conn()
{
	int i;
	tcp_conn_t *tcp_conn;
	int state;

	for (i=TCP_PORT_NR, tcp_conn= tcp_conn_table+i;
		i<TCP_CONN_NR; i++, tcp_conn++)
		/* the first TCP_PORT_NR connection are reserved for
			RSTs */
	{
		if (tcp_conn->tc_flags == TCF_EMPTY)
		{
			tcp_conn->tc_connuser= NULL;
			tcp_conn->tc_mainuser= NULL;
			return tcp_conn;
		}
		if (tcp_conn->tc_mainuser)
			continue;
		if (tcp_conn->tc_senddis > get_time())
			continue;
		if (tcp_conn->tc_state != TCS_CLOSED)
		{
#if DEBUG
 { where(); printf("calling tcp_close_connection\n"); }
#endif
			 tcp_close_connection (tcp_conn, ENOCONN);
		}
		return tcp_conn;
	}
	return NULL;
}


/*
find_conn_entry

This function return a connection matching locport, locaddr, remport, remaddr.
If no such connection exists NULL is returned.
If a connection exists without mainuser it is closed.
*/

PRIVATE tcp_conn_t *find_conn_entry(locport, locaddr, remport, remaddr)
tcpport_t locport;
ipaddr_t locaddr;
tcpport_t remport;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -