【lwip】11-UDP协议&源码分析( 四 )

  • 如果为0,则调用udp_new_port()生成一个并绑定 。
  • 如果不为0,则遍历udp_pcbs链表,判断是否有其它UDP控制块重复使用这个端口号 。确保一个UDP报文最多只有一个应用程序去向 。相同条件:端口号相同且IP报文能到达这个服务 。IP报文能否到达这个服务,可以通过以下判断(其一即符合要求):重复端口号的UDP控制块绑定的IP对比当前UDP控制块需要绑定的IP 。
    1. 两个IP一致 。
    2. 任一IP为全0 。(出现万能IP)
    3. 如果开启了SO_REUSE且两个UDP控制块都配置了SO_REUSEADDR功能 , 则不用对比了,直接支持复用 。
  • 这里需要注意是否开启SO_REUSEADDR选项,即是立即启用端口号的功能 。由宏SO_REUSE决定有没有这个功能 , 用户在代码中设置SO_REUSEADDR是否开启该功能 。
  • 把需要绑定的IP和端口号填入UDP控制块 。绑定成功 。
  • 确保当前UDP控制块插入了udp_pcbs链表 。
  • /** * @ingroup udp_raw * 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_ANY_TYPE 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 occurred. * - ERR_USE. The specified ipaddr and port are already bound to by * another UDP PCB. * * @see udp_disconnect() */err_tudp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port){struct udp_pcb *ipcb;u8_t rebind;#if LWIP_IPV6 && LWIP_IPV6_SCOPESip_addr_t zoned_ipaddr;#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */LWIP_ASSERT_CORE_LOCKED();#if LWIP_IPV4/* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */if (ipaddr == NULL) {ipaddr = IP4_ADDR_ANY; /* 如果传入绑定本地IP为NULL,则绑定为全0 , 表示任意本地IP */}#else /* LWIP_IPV4 */LWIP_ERROR("udp_bind: invalid ipaddr", ipaddr != NULL, return ERR_ARG);#endif /* LWIP_IPV4 */LWIP_ERROR("udp_bind: invalid pcb", pcb != NULL, return ERR_ARG);LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, ipaddr);LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));rebind = 0;/* 检查下当前UDP控制块是否已经插入到udp_pcbs链表中 , 如果插入了,后面绑定成功后就不需要重新插入了 */for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {if (pcb == ipcb) {rebind = 1;break;}}#if LWIP_IPV6 && LWIP_IPV6_SCOPES /* IPV6暂时跳过 *//* If the given IP address should have a zone but doesn't, assign one now.* This is legacy support: scope-aware callers should always provide properly* zoned source addresses. Do the zone selection before the address-in-use* check below; as such we have to make a temporary copy of the address. */if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNKNOWN)) {ip_addr_copy(zoned_ipaddr, *ipaddr);ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr));ipaddr = &zoned_ipaddr;}#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES *//* 确定下本地端口号 */if (port == 0) {port = udp_new_port(); /* 如果没有指定端口号,则由内部生成一个临时端口号 */if (port == 0) { /* 端口号资源不足,申请失败 */LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));return ERR_USE;}} else { /* 端口号申请成功 *//* 检查下有没有其它UDP控制块绑定了相同端口号且IP报文能到达这个服务,这样的话可能会导致一个UDP包有多个应用程序去向 。*/for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {if (pcb != ipcb) { /* 需要跳过当前UDP控制块 */#if SO_REUSE /* 支持`SO_REUSEADDR`选项:立即启用端口号 */if (!ip_get_option(pcb, SOF_REUSEADDR) ||!ip_get_option(ipcb, SOF_REUSEADDR)) /* 两个其中一个没有设置SO_REUSEADDR选项功能,则不能重复使用能到达该IP下的相同端口号 */#endif /* SO_REUSE */{if ((ipcb->local_port == port) && /* 端口号相同 */(((IP_GET_TYPE(&ipcb->local_ip) == IP_GET_TYPE(ipaddr)) &&(ip_addr_eq(&ipcb->local_ip, ipaddr) ||ip_addr_isany(ipaddr) ||ip_addr_isany(&ipcb->local_ip))) ||(IP_GET_TYPE(&ipcb->local_ip) == IPADDR_TYPE_ANY) ||(IP_GET_TYPE(ipaddr) == IPADDR_TYPE_ANY))) {/* 端口号相同且(IP一致或有任意IP),则这个UDP报文到达应用程序就没有唯一性 。错误 */LWIP_DEBUGF(UDP_DEBUG,("udp_bind: local port %"U16_F" already bound by another pcb\n", port));return ERR_USE;}}}}}/* 到此,相关数据检查完毕,符合要求 */ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); /* 绑定本地IP */pcb->local_port = port; /* 绑定本地端口号 */mib2_udp_bind(pcb);/* UDP控制块还没有激活就需要激活:插入udp_pcbs链表 */if (rebind == 0) {pcb->next = udp_pcbs;udp_pcbs = pcb;}LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to "));ip_addr_debug_print_val(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, pcb->local_ip);LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port));return ERR_OK; /* 绑定成功 */}

    推荐阅读