1、结构体声明
udp报文结构示意图

#define UDP_HLEN 8 //udp首部长度
PACK_STRUCT_BEGIN
struct udp_hdr {
PACK_STRUCT_FIELD(u16_t src);
PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */
PACK_STRUCT_FIELD(u16_t len);
PACK_STRUCT_FIELD(u16_t chksum);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
udp_pcb控制块声明
#define IP_PCB ip_addr_t local_ip; ip_addr_t remote_ip; u8_t so_options; u8_t tos; u8_t ttl
struct udp_pcb {
/* Common members of all PCB types */
IP_PCB;
struct udp_pcb *next;
u8_t flags;
u16_t local_port, remote_port;
udp_recv_fn recv; //接收回调函数
void *recv_arg; //接收回调函数的参数
};
typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *addr, u16_t port); //回调函数的typedef定义
struct udp_pcb *udp_pcbs; //udp控制块链表头
2、UDP底层接口函数——udp_input
void udp_input(struct pbuf *p, struct netif *inp)
{
struct udp_hdr *udphdr;
struct udp_pcb *pcb, *prev;
struct udp_pcb *uncon_pcb;
struct ip_hdr *iphdr;
u16_t src, dest;
u8_t local_match;
u8_t broadcast;
iphdr = (struct ip_hdr *)p->payload;
//检查数据的合法性,并移动指针至udp的头部
if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
pbuf_free(p);
goto end;
}
udphdr = (struct udp_hdr *)p->payload;
//检查该IP是否为广播地址
broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp);
src = ntohs(udphdr->src); //源端口号
dest = ntohs(udphdr->dest); //目地端口号
{
prev = NULL;
local_match = 0; //与本地连接IP和端口号是否相同标志
uncon_pcb = NULL; //未连接控制块
//查找udp_pcb控制块
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
local_match = 0;
if (pcb->local_port == dest) {
if (
(!broadcast && ip_addr_isany(&pcb->local_ip)) ||
ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) ||
(broadcast && (ip_addr_isany(&pcb->local_ip) ||
ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) {
local_match = 1;
if ((uncon_pcb == NULL) &&
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
uncon_pcb = pcb;
}
}
}
if ((local_match != 0) &&
(pcb->remote_port == src) &&
(ip_addr_isany(&pcb->remote_ip) ||
ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) {
//连接状态的pcb放置在pcb控制块首部
if (prev != NULL) {
prev->next = pcb->next;
pcb->next = udp_pcbs;
udp_pcbs = pcb;
} else {
UDP_STATS_INC(udp.cachehit);
}
break;
}
prev = pcb;
}
if (pcb == NULL) {
pcb = uncon_pcb;
}
}
//对接收的udp报文伪首部校验
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) {
{
if (udphdr->chksum != 0) {
if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
IP_PROTO_UDP, p->tot_len) != 0) {
pbuf_free(p);
goto end;
}
}
}
if(pbuf_header(p, -UDP_HLEN)) {
pbuf_free(p);
goto end;
}
if (pcb != NULL) {
//调用pcb接收回调函数处理接收的数据包
if (pcb->recv != NULL) {
pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
} else {
pbuf_free(p);
goto end;
}
} else {
pbuf_free(p);
}
} else {
pbuf_free(p);
}
end:
PERF_STOP("udp_input");
}
3、应用层接口函数
(1)发送函数
err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
{
return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
}
err_t udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *dst_ip, u16_t dst_port)
{
struct netif *netif;
netif = ip_route(dst_ip); //查找网络接口
if (netif == NULL) {
return ERR_RTE;
}
return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
}
err_t udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif)
{
struct udp_hdr *udphdr;
ip_addr_t *src_ip;
err_t err;
struct pbuf *q; /* q will be sent down the stack */
if (pcb->local_port == 0) {
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
if (err != ERR_OK) {
return err;
}
}
//判断pbuf是否能够容纳UDP_HLEN的空间,若无则申请。
if (pbuf_header(p, UDP_HLEN)) {
//申请PBUF_RAM类型的RAM空间 大小为PBUF_LINK_HLEN + PBUF_IP_HLEN + UDP_HLEN
q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
/* new header pbuf could not be allocated? */
if (q == NULL) {
return ERR_MEM;
}
if (p->tot_len != 0) {
//连接两个pbuf q 和pbuf p
pbuf_chain(q, p);
}
} else {
//pbuf中已经为udp头部预留了空间
q = p;
}
udphdr = (struct udp_hdr *)q->payload;
udphdr->src = htons(pcb->local_port);
udphdr->dest = htons(dst_port);
/* in UDP, 0 checksum means 'no checksum' */
udphdr->chksum = 0x0000;
if (ip_addr_isany(&pcb->local_ip)) {
src_ip = &(netif->ip_addr);
} else {
if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
if (q != p) {
pbuf_free(q);
q = NULL;
}
return ERR_VAL;
}
src_ip = &(pcb->local_ip);
}
{
udphdr->len = htons(q->tot_len);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
u16_t udpchksum;
{
udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
}
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udpchksum == 0x0000) {
udpchksum = 0xffff;
}
udphdr->chksum = udpchksum;
}
#endif /* CHECKSUM_GEN_UDP */
//调用ip层发送函数发送
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
}
//新申请的pbuf q需释放
if (q != p) {
pbuf_free(q);
q = NULL;
}
return err;
}
(2)控制块的相关操作函数
新建控制块,pcb->ttl = UDP_TTL;
#define UDP_TTL 255
struct udp_pcb *udp_new(void)
{
struct udp_pcb *pcb;
pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);
if (pcb != NULL) {
memset(pcb, 0, sizeof(struct udp_pcb));
pcb->ttl = UDP_TTL; //生存周期
}
return pcb;
}
绑定某一个本地ip地址和端口号,即设置pcb->local_port,pcb->local_ip
err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
u8_t rebind;
rebind = 0;
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
if (pcb == ipcb) {
rebind = 1;
}
if ((ipcb->local_port == port) &&(ip_addr_isany(&(ipcb->local_ip)) ||
ip_addr_isany(ipaddr) || ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
return ERR_USE;
}
ip_addr_set(&pcb->local_ip, ipaddr); //设置pcb控制块中的本地ip
if (port == 0) {
port = udp_new_port(); //申请一个新的端口号
if (port == 0) {
return ERR_USE;
}
}
pcb->local_port = port; ////设置pcb控制块中的本地端口号
if (rebind == 0) {
pcb->next = udp_pcbs;
udp_pcbs = pcb;
}
return ERR_OK;
}
连接远程主机ip号和端口号,设置pcb->remote_ip, pcb->remote_port
err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
if (pcb->local_port == 0) {
err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
if (err != ERR_OK) {
return err;
}
}
ip_addr_set(&pcb->remote_ip, ipaddr);
pcb->remote_port = port;
pcb->flags |= UDP_FLAGS_CONNECTED;
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
if (pcb == ipcb) {
return ERR_OK;
}
}
pcb->next = udp_pcbs;
udp_pcbs = pcb;
return ERR_OK;
}
释放某一个pcb
void udp_remove(struct udp_pcb *pcb)
{
struct udp_pcb *pcb2;
if (udp_pcbs == pcb) {
udp_pcbs = udp_pcbs->next;
} else {
for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
if (pcb2->next != NULL && pcb2->next == pcb) {
pcb2->next = pcb->next;
}
}
}
memp_free(MEMP_UDP_PCB, pcb);
}
断开某一个连接
void udp_disconnect(struct udp_pcb *pcb)
{
ip_addr_set_any(&pcb->remote_ip);
pcb->remote_port = 0;
pcb->flags &= ~UDP_FLAGS_CONNECTED;
}
4、udp 应用案列
建立一个udp服务器,回显接收到的数据。
void udp_echoserver_init(void)
{
struct udp_pcb *upcb;
err_t err;
upcb = udp_new();
if (upcb)
{
err = udp_bind(upcb, IP_ADDR_ANY, UDP_SERVER_PORT);
if(err == ERR_OK)
{
//注册回调函数
udp_recv(upcb, udp_echoserver_receive_callback, NULL);
}
else
{
udp_remove(upcb);
printf("can not bind pcb");
}
}
else
{
printf("can not create pcb");
}
}
void udp_echoserver_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
{
udp_connect(upcb, addr, UDP_CLIENT_PORT);
udp_send(upcb, p);
udp_disconnect(upcb);
pbuf_free(p);
}
|