lwip之udp

1、结构体声明

udp报文结构示意图
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(&current_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), &current_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), &current_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, &current_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);

}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值