📄 udp.c
字号:
/*
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 + -