int tport_stream_init_primary(tport_primary_t *pri, su_socket_t socket, tp_name_t tpn[1], su_addrinfo_t *ai, tagi_t const *tags, char const **return_culprit) { pri->pri_primary->tp_socket = socket; /* Set IP TOS if set */ tport_set_tos(socket, ai, pri->pri_params->tpp_tos); #if defined(__linux__) /* Linux does not allow reusing TCP port while this one is open, so we can safely call su_setreuseaddr() before bind(). */ su_setreuseaddr(socket, 1); #endif if (tport_bind_socket(socket, ai, return_culprit) == -1) return -1; if (listen(socket, pri->pri_params->tpp_qsize) == SOCKET_ERROR) return *return_culprit = "listen", -1; #if !defined(__linux__) /* Allow reusing TCP sockets * * On Solaris & BSD, call setreuseaddr() after bind in order to avoid * binding to a port owned by an existing server. */ su_setreuseaddr(socket, 1); #endif pri->pri_primary->tp_events = SU_WAIT_ACCEPT; pri->pri_primary->tp_conn_orient = 1; return 0; }
int tport_udp_init_primary(tport_primary_t *pri, tp_name_t tpn[1], su_addrinfo_t *ai, tagi_t const *tags, char const **return_culprit) { unsigned rmem = 0, wmem = 0; int events = SU_WAIT_IN; int s; #if HAVE_IP_ADD_MEMBERSHIP su_sockaddr_t *su = (su_sockaddr_t *)ai->ai_addr; #endif int const one = 1; (void)one; s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (s == INVALID_SOCKET) return *return_culprit = "socket", -1; pri->pri_primary->tp_socket = s; if (tport_bind_socket(s, ai, return_culprit) < 0) return -1; tport_set_tos(s, ai, pri->pri_params->tpp_tos); #if HAVE_IP_ADD_MEMBERSHIP if (ai->ai_family == AF_INET && IN_MULTICAST(ntohl(su->su_sin.sin_addr.s_addr))) { /* Try to join to the multicast group */ /* Bind to the SIP address like <sip:88.77.66.55:5060;maddr=224.0.1.75;transport=udp> */ struct ip_mreq imr[1]; struct in_addr iface; memset(imr, 0, sizeof imr); imr->imr_multiaddr = su->su_sin.sin_addr; if (host_is_ip4_address(tpn->tpn_canon) && su_inet_pton(AF_INET, tpn->tpn_canon, &iface) > 0) { imr->imr_interface = iface; } if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, imr, (sizeof imr)) < 0) { SU_DEBUG_3(("setsockopt(%s): %s\n", "IP_ADD_MEMBERSHIP", su_strerror(su_errno()))); } #if HAVE_IP_MULTICAST_LOOP else if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof one) < 0) { SU_DEBUG_3(("setsockopt(%s): %s\n", "IP_MULTICAST_LOOP", su_strerror(su_errno()))); } #endif } #endif #if HAVE_IP_MTU_DISCOVER { /* Turn off DF flag on Linux */ int dont = IP_PMTUDISC_DONT; if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &dont, sizeof(dont)) < 0) { SU_DEBUG_3(("setsockopt(%s): %s\n", "IP_MTU_DISCOVER", su_strerror(su_errno()))); } } #endif #if HAVE_IP_RECVERR if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { if (setsockopt(s, IPPROTO_IP, IP_RECVERR, &one, sizeof(one)) < 0) { if (ai->ai_family == AF_INET) SU_DEBUG_3(("setsockopt(%s): %s\n", "IPVRECVERR", su_strerror(su_errno()))); } events |= SU_WAIT_ERR; } #endif #if HAVE_IPV6_RECVERR if (ai->ai_family == AF_INET6) { if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0) SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno()))); events |= SU_WAIT_ERR; } #endif tl_gets(tags, TPTAG_UDP_RMEM_REF(rmem), TPTAG_UDP_WMEM_REF(wmem), TAG_END()); if (rmem != 0 && #if HAVE_SO_RCVBUFFORCE setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&rmem, sizeof rmem) < 0 && #endif setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *)&rmem, sizeof rmem) < 0) { SU_DEBUG_3(("setsockopt(SO_RCVBUF): %s\n", su_strerror(su_errno()))); } if (wmem != 0 && #if HAVE_SO_SNDBUFFORCE setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void *)&wmem, sizeof wmem) < 0 && #endif setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *)&wmem, sizeof wmem) < 0) { SU_DEBUG_3(("setsockopt(SO_SNDBUF): %s\n", su_strerror(su_errno()))); } pri->pri_primary->tp_events = events; tport_init_compressor(pri->pri_primary, tpn->tpn_comp, tags); tport_check_trunc(pri->pri_primary, ai); #if HAVE_SOFIA_STUN tport_stun_server_add_socket(pri->pri_primary); #endif return 0; }