【LwIP - UDP】 - udp_bind和udp_connect分析

目录less

前言dom

1 udp_bindthis

2  udp_connectspa

 


前言

udp_bind和udp_connect二者具体的工做原理,笔者在网上找不到正确的说法。对此,笔者主要对UDP中的这两个接口进行分析。debug

1 udp_bind

udp_bind将一个UDP PCB与IP和端口进行绑定。固然不是简简单单的把该IP和端口记录到UDP PCB中。会作以下的操做:调试

(1)  判断UDP PCB是否早存在于链表中,同时也判断要绑定的端口port是否已经被链表中的某一个PCB绑定且IP是否一致。只要端口和IP没有被链表中的PCB绑定,则能正常的为新的UDP PCB绑定或者已有的UDP PCB重绑定。code

(2)  第(1)经过的话,会为UDP PCB设置IP,以及端口。至于端口,若是port为0,则会自动分配一个端口。接口

(3) UDP PCB若是是新的PCB,则将入UDP PCB链表中。ip

/**
 * Bind an UDP PCB.
 *
 * @param pcb UDP PCB to be bound with a local address ipaddr and port.
 * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
 * bind to all local interfaces.
 * @param port local UDP port to bind with. Use 0 to automatically bind
 * to a random port between UDP_LOCAL_PORT_RANGE_START and
 * UDP_LOCAL_PORT_RANGE_END.
 *
 * ipaddr & port are expected to be in the same byte order as in the pcb.
 *
 * @return lwIP error code.
 * - ERR_OK. Successful. No error occured.
 * - ERR_USE. The specified ipaddr and port are already bound to by
 * another UDP PCB.
 *
 * @see udp_disconnect()
 */
err_t
udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
  struct udp_pcb *ipcb;
  u8_t rebind;
	// [2018年9月7日14:52:39] 下列3行调试信息
  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
  ip_addr_debug_print(UDP_DEBUG, ipaddr);
  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));

  rebind = 0;
  /* Check for double bind and rebind of the same pcb */
  // [2018年9月7日15:00:02] 检查相同的PCB双重绑定和重绑定
  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
    /* is this UDP PCB already on active list? */
	// [2018年9月7日15:02:31] 判断这个UDP PCB是否早存在于链表中
    if (pcb == ipcb) {
      /* pcb may occur at most once in active list */
      LWIP_ASSERT("rebind == 0", rebind == 0);
      /* pcb already in list, just rebind */
	  // [2018年9月7日15:03:43] PCB早存在于链表中,则重绑定
      rebind = 1;
    }

    /* By default, we don't allow to bind to a port that any other udp
       PCB is alread bound to, unless *all* PCBs with that port have tha
       REUSEADDR flag set. */
	// [2018年9月7日15:14:02] 默认状况下,咱们不容许一个已被绑定过的端口再次绑定,除非PCB设置了REUSEADDR标志
 
#if SO_REUSE
    else if (!ip_get_option(pcb, SOF_REUSEADDR) &&
             !ip_get_option(ipcb, SOF_REUSEADDR)) {
#else /* SO_REUSE */
    /* port matches that of PCB in list and REUSEADDR not set -> reject */
	// [2018年9月7日15:17:40] port与链表中的PCB进行匹配,而且REUSEADDR没有设置
    else {
#endif /* SO_REUSE */
			// [2018年9月7日15:21:35] port与链表中的PCB的local_port匹配 
      if ((ipcb->local_port == port) &&
          /* IP address matches, or one is IP_ADDR_ANY? */
		  // [2018年9月7日15:36:43] IP地址匹配或者是一个IP_ADDR_ANY
          (ip_addr_isany(&(ipcb->local_ip)) ||
           ip_addr_isany(ipaddr) ||
           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
        /* other PCB already binds to this local IP and port */
		// 已经有其它的PCB早已绑定了该IP和端口
        LWIP_DEBUGF(UDP_DEBUG,
                    ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
        return ERR_USE;
      }
    }
  }
	
	
  // IP或者端口没被其它PCB绑定
  ip_addr_set(&pcb->local_ip, ipaddr);

  /* no port specified? */
  // [2018年9月7日15:09:59] 没有指定端口
  if (port == 0) {
    // [2018年9月7日15:10:23] 自动分配端口
    port = udp_new_port();
    if (port == 0) {
      /* no more ports available in local range */
	  // [2018年9月7日15:10:37] 返回的端口为0,则没有有效的端口了
      LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
      return ERR_USE;
    }
  }
	
  // [2018年9月7日15:11:23] 为PCB块设置端口号
  pcb->local_port = port;
  snmp_insert_udpidx_tree(pcb);
  /* pcb not active yet? */
  // 该PCB未有效,即未加入链表,则将其加入链表
  if (rebind == 0) {
    /* place the PCB on the active list if not already there */
    pcb->next = udp_pcbs;
    udp_pcbs = pcb;
  }
  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
              ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
               ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
               ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
               pcb->local_port));
  return ERR_OK;
}

 

2  udp_connect

udp_connect将一个UDP PCB与远端IP和端口进行绑定。若是UDP PCB是新分配的,则默认绑定到本地地址以及自动分配的端口。若是UDP PCB已经绑定过端口,则会重绑定远端IP和端口。若是用户若是要从新绑定本地地址和端口,可在udp_connect以前或者以后调用udp_bind()便可。udp_connect的操做很少,以下:ci

(1) 检查UDP PCB是否已绑定本地端口。若是本地端口为0(即没有绑定),则调用udp_bind()自动分配一个端口并绑定。

(2) 绑定远端IP和端口,并将UDP PCB的标志设置为UDP_FLAGS_CONNECTED。

(3) 将UDP PCB加入UDP PCBs链表中,若是早已存在则忽略。

/**
 * Connect an UDP PCB.
 *
 * This will associate the UDP PCB with the remote address.
 *
 * @param pcb UDP PCB to be connected with remote address ipaddr and port.
 * @param ipaddr remote IP address to connect with.
 * @param port remote UDP port to connect with.
 *
 * @return lwIP error code
 *
 * ipaddr & port are expected to be in the same byte order as in the pcb.
 *
 * The udp pcb is bound to a random local port if not already bound.
 *
 * @see udp_disconnect()
 */
err_t
udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
  struct udp_pcb *ipcb;

  if (pcb->local_port == 0) {				
    // [2018年9月7日16:35:58] // 若是pcb是新分配的,则pcb采用本地IP以及自动分配的端口   	
    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);	// [2018年9月7日16:33:19] 为UDP PCB设置远程IP												
  pcb->remote_port = port;							// [2018年9月7日16:33:19] 为UDP PCB设置端口
  pcb->flags |= UDP_FLAGS_CONNECTED;
/** TODO: this functionality belongs in upper layers */
#ifdef LWIP_UDP_TODO
  /* Nail down local IP for netconn_addr()/getsockname() */
  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
    struct netif *netif;

    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
      LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
      UDP_STATS_INC(udp.rterr);
      return ERR_RTE;
    }
    /** TODO: this will bind the udp pcb locally, to the interface which
        is used to route output packets to the remote address. However, we
        might want to accept incoming packets on any interface! */
    pcb->local_ip = netif->ip_addr;
  } else if (ip_addr_isany(&pcb->remote_ip)) {
    pcb->local_ip.addr = 0;
  }
#endif
  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
              ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
               ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
               ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
               pcb->local_port));

  /* Insert UDP PCB into the list of active UDP PCBs. */
	// 将UDP PCB插入有效的UDP PCBs链表中(固然,若是前面调用udp_bind()且正常返回,其会将PCB插入链表)
  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
    if (pcb == ipcb) {
      /* already on the list, just return */
      return ERR_OK;
    }
  }
  /* PCB not yet on the list, add PCB now */
  pcb->next = udp_pcbs;
  udp_pcbs = pcb;
  return ERR_OK;
}