/*! Perform system bind on the OS backing socket. * \param ep Endpoint context * \param fd Callers FD * \param ip_addr_be32 Local address to which to bind * \param port_be16 [in] requested port [out] assigned port * \return 0 - success & [port_be16] updated * CI_SOCKET_HANDOVER, Pass to OS, OS bound ok, (no error) * CI_SOCKET_ERROR & errno set */ ci_inline int __ci_bind(ci_netif *ni, ci_sock_cmn *s, ci_uint32 ip_addr_be32, ci_uint16* port_be16 ) { int rc; ci_uint16 user_port; /* Port number specified by user, not by OS. * See bug 4015 for details */ union ci_sockaddr_u sa_u; ci_assert(s->domain == AF_INET || s->domain == AF_INET6); ci_assert( port_be16 ); user_port = *port_be16; #if CI_CFG_FAKE_IPV6 ci_assert(s->domain == AF_INET || s->domain == AF_INET6); if( s->domain == AF_INET ) ci_make_sockaddr(&sa_u.sin, s->domain, user_port, ip_addr_be32); else ci_make_sockaddr6(&sa_u.sin6, s->domain, user_port, ip_addr_be32); #else ci_assert(s->domain == AF_INET); ci_make_sockaddr(&sa_u.sin, s->domain, user_port, ip_addr_be32); #endif #ifdef __ci_driver__ rc = efab_tcp_helper_bind_os_sock(netif2tcp_helper_resource(ni), SC_SP(s), &sa_u.sa, sizeof(sa_u), port_be16); #else rc = ci_tcp_helper_bind_os_sock(ni, SC_SP(s), &sa_u.sa, sizeof(sa_u), port_be16); #endif /* bug1781: only do this if the earlier bind succeeded. * check if we can handle this socket */ if( rc != 0 ) return rc; if( user_port != 0 ) s->s_flags |= CI_SOCK_FLAG_PORT_BOUND; if( ip_addr_be32 != INADDR_ANY ) s->s_flags |= CI_SOCK_FLAG_ADDR_BOUND; s->s_flags &= ~CI_SOCK_FLAG_CONNECT_MUST_BIND; #ifndef __ci_driver__ /* We do not call bind() to alien address from in-kernel code */ if( ip_addr_be32 != INADDR_ANY && !cicp_user_addr_is_local_efab(CICP_HANDLE(ni), &ip_addr_be32) ) s->s_flags |= CI_SOCK_FLAG_BOUND_ALIEN; #endif return rc; }
/* To handle bind we just let the underlying OS socket make all * of the decisions for us. If The bind leaves things such that * the source address is not one of ours then we hand it over to the * OS (by returning CI_SOCKET_HANDOVER) - in which case the OS socket * will be bound as expected. */ int ci_udp_bind(citp_socket* ep, ci_fd_t fd, const struct sockaddr* addr, socklen_t addrlen) { int rc; ci_uint16 local_port; CHECK_UEP(ep); LOG_UC(log("%s("SF_FMT", addrlen=%d)", __FUNCTION__, SF_PRI_ARGS(ep,fd), addrlen)); /* Make sure we have no filters. * * ?? TODO: Under what circumstances could we possibly have filters here? * _WIN32 only perhaps? */ ci_udp_clr_filters(ep); rc = ci_tcp_helper_bind_os_sock(fd, addr, addrlen, &local_port); if( rc == CI_SOCKET_ERROR ) return rc; return ci_udp_bind_conclude(ep, addr, local_port ); }