1、结构体声明
udp报文结构示意图
#define UDP_HLEN 8
PACK_STRUCT_BEGIN
struct udp_hdr {
PACK_STRUCT_FIELD(u16_t src);
PACK_STRUCT_FIELD(u16_t dest);
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 {
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);
struct udp_pcb *udp_pcbs;
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;
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;
broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp);
src = ntohs(udphdr->src);
dest = ntohs(udphdr->dest);
{
prev = NULL;
local_match = 0;
uncon_pcb = NULL;
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))) {
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;
}
}
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) {
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;
if (pcb->local_port == 0) {
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
if (err != ERR_OK) {
return err;
}
}
if (pbuf_header(p, UDP_HLEN)) {
q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
if (q == NULL) {
return ERR_MEM;
}
if (p->tot_len != 0) {
pbuf_chain(q, p);
}
} else {
q = p;
}
udphdr = (struct udp_hdr *)q->payload;
udphdr->src = htons(pcb->local_port);
udphdr->dest = htons(dst_port);
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);
#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);
}
if (udpchksum == 0x0000) {
udpchksum = 0xffff;
}
udphdr->chksum = udpchksum;
}
#endif
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
}
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);
if (port == 0) {
port = udp_new_port();
if (port == 0) {
return ERR_USE;
}
}
pcb->local_port = port;
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);
}