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

📄 udp.c

📁 minux的源代码,一个非常小的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
udp.c
*/

#include "inet.h"

#include "assert.h"
#include "buf.h"
#include "clock.h"
#include "io.h"
#include "ip.h"
#include "sr.h"
#include "type.h"
#include "udp.h"

INIT_PANIC();

#define UDP_PORT_NR	1
#define UDP_FD_NR	32

typedef struct udp_port
{
	int up_flags;
	int up_state;
	int up_ipfd;
	int up_minor;
	int up_ipdev;
	acc_t *up_wr_pack;
	ipaddr_t up_ipaddr;
	struct udp_fd *up_next_fd;
	struct udp_fd *up_write_fd;
} udp_port_t;

#define UPF_EMPTY	0x0
#define UPF_WRITE_IP	0x1
#define UPF_WRITE_SP	0x2
#define UPF_READ_IP	0x4
#define UPF_READ_SP	0x8
#define UPF_SUSPEND	0x10
#define UPF_MORE2WRITE	0x20

#define UPS_EMPTY	0
#define UPS_SETPROTO	1
#define UPS_GETCONF	2
#define UPS_MAIN	3
#define UPS_ERROR	4

typedef struct udp_fd
{
	int uf_flags;
	udp_port_t *uf_port;
	int uf_ioreq;
	int uf_srfd;
	nwio_udpopt_t uf_udpopt;
	get_userdata_t uf_get_userdata;
	put_userdata_t uf_put_userdata;
	acc_t *uf_pack;
	acc_t *uf_rd_buf;
	size_t uf_rd_count;
	size_t uf_wr_count;
	time_t uf_exp_tim;
} udp_fd_t;

#define UFF_EMPTY	0x0
#define UFF_INUSE	0x1
#define UFF_IOCTL_IP	0x2
#define UFF_READ_IP	0x4
#define UFF_WRITE_IP	0x8
#define UFF_OPTSET	0x10

FORWARD void read_ip_packets ARGS(( udp_port_t *udp_port ));
FORWARD void udp_buffree ARGS(( int priority, size_t reqsize ));
FORWARD void udp_main ARGS(( udp_port_t *udp_port ));
FORWARD acc_t *udp_get_data ARGS(( int fd, size_t offset, size_t count, 
	int for_ioctl ));
FORWARD int udp_put_data ARGS(( int fd, size_t offset, acc_t *data, 	
	int for_ioctl ));
FORWARD void udp_restart_write_port ARGS(( udp_port_t *udp_port ));
FORWARD void process_inc_fragm ARGS(( udp_port_t *udp_port, acc_t *data ));
FORWARD int reply_thr_put ARGS(( udp_fd_t *ucp_fd, int reply,
	int for_ioctl ));
FORWARD void reply_thr_get ARGS(( udp_fd_t *udp_fd, int reply,
	int for_ioctl ));
FORWARD int udp_setopt ARGS(( udp_fd_t *udp_fd ));
FORWARD udpport_t find_unused_port ARGS(( int fd ));
FORWARD int is_unused_port ARGS(( Udpport_t port ));
FORWARD int udp_packet2user ARGS(( udp_fd_t *udp_fd ));
FORWARD void restart_write_fd ARGS(( udp_fd_t *udp_fd ));
FORWARD u16_t pack_oneCsum ARGS(( acc_t *pack ));

PRIVATE udp_port_t udp_port_table[UDP_PORT_NR];
PRIVATE udp_fd_t udp_fd_table[UDP_FD_NR];

PUBLIC void udp_init()
{
	udp_fd_t *udp_fd;
	udp_port_t *udp_port;
	int i, result;

	assert (BUF_S >= sizeof(struct nwio_ipopt));
	assert (BUF_S >= sizeof(struct nwio_ipconf));
	assert (BUF_S >= sizeof(struct nwio_udpopt));
	assert (BUF_S >= sizeof(struct udp_io_hdr));
	assert (UDP_HDR_SIZE == sizeof(udp_hdr_t));
	assert (UDP_IO_HDR_SIZE == sizeof(udp_io_hdr_t));

	udp_port_table[0].up_minor= UDP_DEV0;
	udp_port_table[0].up_ipdev= IP0;

	for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
	{
		udp_fd->uf_flags= UFF_EMPTY;
	}

	bf_logon(udp_buffree);

	for (i= 0, udp_port= udp_port_table; i<UDP_PORT_NR; i++, udp_port++)
	{
		udp_port->up_flags= UPF_EMPTY;
		udp_port->up_state= UPS_EMPTY;
		udp_port->up_next_fd= udp_fd_table;
		udp_port->up_write_fd= NULL;

		result= sr_add_minor (udp_port->up_minor,
			udp_port-udp_port_table, udp_open, udp_close, udp_read,
			udp_write, udp_ioctl, udp_cancel);
		assert (result >= 0);

		udp_main(udp_port);
	}
}

PRIVATE void udp_main(udp_port)
udp_port_t *udp_port;
{
	udp_fd_t *udp_fd;
	int result, i;

	switch (udp_port->up_state)
	{
	case UPS_EMPTY:
		udp_port->up_state= UPS_SETPROTO;

		udp_port->up_ipfd= ip_open(udp_port->up_ipdev, 
			udp_port-udp_port_table, udp_get_data, udp_put_data);
		if (udp_port->up_ipfd < 0)
		{
			udp_port->up_state= UPS_ERROR;
			printf("%s, %d: unable to open ip port\n", __FILE__,
				__LINE__);
			return;
		}

		result= ip_ioctl(udp_port->up_ipfd, NWIOSIPOPT);
		if (result == NW_SUSPEND)
			udp_port->up_flags |= UPF_SUSPEND;
		if (result<0)
		{
			return;
		}
		if (udp_port->up_state != UPS_GETCONF)
			return;
		/* drops through */
	case UPS_GETCONF:
		udp_port->up_flags &= ~UPF_SUSPEND;

		result= ip_ioctl(udp_port->up_ipfd, NWIOGIPCONF);
		if (result == NW_SUSPEND)
			udp_port->up_flags |= UPF_SUSPEND;
		if (result<0)
		{
			return;
		}
		if (udp_port->up_state != UPS_MAIN)
			return;
		/* drops through */
	case UPS_MAIN:
		udp_port->up_flags &= ~UPF_SUSPEND;

		for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
		{
			if (!(udp_fd->uf_flags & UFF_INUSE))
				continue;
			if (udp_fd->uf_port != udp_port)
				continue;
			if (udp_fd->uf_flags & UFF_IOCTL_IP)
				udp_ioctl(i, udp_fd->uf_ioreq);
		}
		read_ip_packets(udp_port);
		return;
	default:
#if DEBUG
 { where(); printf("udp_port_table[%d].up_state= %d\n", udp_port-udp_port_table,
	udp_port->up_state); }
#endif
		ip_panic(( "unknown state" ));
		break;
	}
}

int udp_open (port, srfd, get_userdata, put_userdata)
int port;
int srfd;
get_userdata_t get_userdata;
put_userdata_t put_userdata;
{
	int i;
	udp_fd_t *udp_fd;

	for (i= 0; i<UDP_FD_NR && (udp_fd_table[i].uf_flags & UFF_INUSE);
		i++);

	if (i>= UDP_FD_NR)
	{
#if DEBUG
 { where(); printf("out of fds\n"); }
#endif
		return EOUTOFBUFS;
	}

	udp_fd= &udp_fd_table[i];

	udp_fd->uf_flags= UFF_INUSE;
	udp_fd->uf_port= &udp_port_table[port];
	udp_fd->uf_srfd= srfd;
	udp_fd->uf_udpopt.nwuo_flags= UDP_DEF_OPT;
	udp_fd->uf_get_userdata= get_userdata;
	udp_fd->uf_put_userdata= put_userdata;
	udp_fd->uf_pack= 0;

	return i;

}

PRIVATE acc_t *udp_get_data (port, offset, count, for_ioctl)
int port;
size_t offset;
size_t count;
int for_ioctl;
{
	udp_port_t *udp_port;
	udp_fd_t *udp_fd;
	int result;

	udp_port= &udp_port_table[port];

	switch(udp_port->up_state)
	{
	case UPS_SETPROTO:
assert (for_ioctl);
		if (!count)
		{
			result= (int)offset;
			if (result<0)
			{
				udp_port->up_state= UPS_ERROR;
				break;
			}
			udp_port->up_state= UPS_GETCONF;
			if (udp_port->up_flags & UPF_SUSPEND)
				udp_main(udp_port);
			return NULL;
		}
		else
		{
			struct nwio_ipopt *ipopt;
			acc_t *acc;

assert (!offset);
assert (count == sizeof(*ipopt));

			acc= bf_memreq(sizeof(*ipopt));
			ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
			ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC | 
				NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC |
				NWIO_HDR_O_ANY | NWIO_RWDATALL;
			ipopt->nwio_proto= IPPROTO_UDP;
			return acc;
		}
	case UPS_MAIN:
assert (!for_ioctl);
assert (udp_port->up_flags & UPF_WRITE_IP);
		if (!count)
		{
			result= (int)offset;
#if DEBUG & 256
 { where(); printf("result of ip_write is %d\n", result); }
#endif
assert (udp_port->up_wr_pack);
			bf_afree(udp_port->up_wr_pack);
			udp_port->up_wr_pack= 0;
			if (udp_port->up_flags & UPF_WRITE_SP)
			{
				if (udp_port->up_write_fd)
				{
					udp_fd= udp_port->up_write_fd;
					udp_port->up_write_fd= NULL;
					udp_fd->uf_flags &= ~UFF_WRITE_IP;
					reply_thr_get(udp_fd, result, FALSE);
				}
				udp_port->up_flags &= ~(UPF_WRITE_SP | 
					UPF_WRITE_IP);
				if (udp_port->up_flags & UPF_MORE2WRITE)
				{
					udp_restart_write_port(udp_port);
				}
			}
			else
				udp_port->up_flags &= ~UPF_WRITE_IP;
		}
		else
		{
			return bf_cut (udp_port->up_wr_pack, offset, count);
		}
		break;
	default:
		printf("udp_get_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n",
			port, offset, count, udp_port->up_state);
		break;
	}
	return NULL;
}

PRIVATE int udp_put_data (fd, offset, data, for_ioctl)
int fd;
size_t offset;
acc_t *data;
int for_ioctl;
{
	udp_port_t *udp_port;
	int result;

	udp_port= &udp_port_table[fd];

	switch (udp_port->up_state)
	{
	case UPS_GETCONF:
		if (!data)
		{
			result= (int)offset;
			if (result<0)
			{
				udp_port->up_state= UPS_ERROR;
				return NW_OK;
			}
			udp_port->up_state= UPS_MAIN;
			if (udp_port->up_flags & UPF_SUSPEND)
				udp_main(udp_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);
			udp_port->up_ipaddr= ipconf->nwic_ipaddr;
			bf_afree(data);
		}
		break;
	case UPS_MAIN:
assert (udp_port->up_flags & UPF_READ_IP);
		if (!data)
		{
			result= (int)offset;
compare (result, >=, 0);
			if (udp_port->up_flags & UPF_READ_SP)
			{
				udp_port->up_flags &= ~(UPF_READ_SP|
					UPF_READ_IP);
				read_ip_packets(udp_port);
			}
			else
				udp_port->up_flags &= ~UPF_READ_IP;
		}
		else
		{
assert (!offset);	/* This isn't a valid assertion but ip sends only
			 * whole datagrams up */
			process_inc_fragm(udp_port, data);
		}
		break;
	default:
		ip_panic((
		"udp_put_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n",
					fd, offset, data, udp_port->up_state ));
	}
	return NW_OK;
}

int udp_ioctl (fd, req)
int fd;
int req;
{
	udp_fd_t *udp_fd;
	udp_port_t *udp_port;
	nwio_udpopt_t *udp_opt;
	acc_t *opt_acc;
	int type;
	int result;

	udp_fd= &udp_fd_table[fd];
	type= req & IOCTYPE_MASK;

assert (udp_fd->uf_flags & UFF_INUSE);

	udp_port= udp_fd->uf_port;
	udp_fd->uf_flags |= UFF_IOCTL_IP;
	udp_fd->uf_ioreq= req;

	if (udp_port->up_state != UPS_MAIN)
		return NW_SUSPEND;

	switch(type)
	{
	case NWIOSUDPOPT & IOCTYPE_MASK:
		if (req != NWIOSUDPOPT)
		{
			reply_thr_get (udp_fd, EBADIOCTL, TRUE);
			result= NW_OK;
			break;
		}
		result= udp_setopt(udp_fd);
		break;
	case NWIOGUDPOPT & IOCTYPE_MASK:
		if (req != NWIOGUDPOPT)
		{
			reply_thr_put(udp_fd, EBADIOCTL, TRUE);
			result= NW_OK;
			break;
		}
		opt_acc= bf_memreq(sizeof(*udp_opt));
assert (opt_acc->acc_length == sizeof(*udp_opt));
		udp_opt= (nwio_udpopt_t *)ptr2acc_data(opt_acc);

		*udp_opt= udp_fd->uf_udpopt;
		udp_opt->nwuo_locaddr= udp_fd->uf_port->up_ipaddr;
		result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, 0, opt_acc,
			TRUE);
		if (result == NW_OK)
			reply_thr_put(udp_fd, NW_OK, TRUE);
		break;
	default:
		reply_thr_get(udp_fd, EBADIOCTL, TRUE);
		result= NW_OK;
		break;
	}
	if (result != NW_SUSPEND)
		udp_fd->uf_flags &= ~UFF_IOCTL_IP;
	return result;
}

PRIVATE int udp_setopt(udp_fd)
udp_fd_t *udp_fd;
{
	udp_fd_t *fd_ptr;
	nwio_udpopt_t oldopt, newopt;
	acc_t *data;
	int result;
	udpport_t port;
	unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags,
		all_flags, flags;
	unsigned long new_flags;
	int i;

#if DEBUG & 256
 { where(); printf("in udp_setopt\n"); }
#endif
	data= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0, 
		sizeof(nwio_udpopt_t), TRUE);

	if (!data)
		return EFAULT;

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

	newopt= *(nwio_udpopt_t *)ptr2acc_data(data);
	bf_afree(data);
	oldopt= udp_fd->uf_udpopt;
#if DEBUG & 256
 { where(); printf("newopt.nwuo_flags= 0x%x, newopt.nwuo_locport= %d, newopt.nwuo_remport= %d\n",
	newopt.nwuo_flags, ntohs(newopt.nwuo_locport),
	ntohs(newopt.nwuo_remport)); }
#endif

	old_en_flags= oldopt.nwuo_flags & 0xffff;
	old_di_flags= (oldopt.nwuo_flags >> 16) & 0xffff;

	new_en_flags= newopt.nwuo_flags & 0xffff;
	new_di_flags= (newopt.nwuo_flags >> 16) & 0xffff;

	if (new_en_flags & new_di_flags)
	{
#if DEBUG
 { where(); printf("returning EBADMODE\n"); }
#endif
		reply_thr_get(udp_fd, EBADMODE, TRUE);
		return NW_OK;
	}

	/* NWUO_ACC_MASK */
	if (new_di_flags & NWUO_ACC_MASK)
	{
#if DEBUG
 { where(); printf("returning EBADMODE\n"); }
#endif
		reply_thr_get(udp_fd, EBADMODE, TRUE);
		return NW_OK;

⌨️ 快捷键说明

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