📄 tport.c
字号:
/** Create a new reference to transport object. */tport_t *tport_incref(tport_t *tp){ return tport_ref(tp);}/** Destroy a transport reference. */void tport_decref(tport_t **ttp){ assert(ttp); if (*ttp) { tport_unref(*ttp); *ttp = NULL; }}/** Get transport parameters. * * @param self pointer to a transport object * @param tag,value,... list of tags */int tport_get_params(tport_t const *self, tag_type_t tag, tag_value_t value, ...){ ta_list ta; int n; tport_params_t const *tpp; tport_primary_t const *pri = self->tp_pri; int connect; if (self == NULL) return su_seterrno(EINVAL); tpp = self->tp_params; ta_start(ta, tag, value); connect = tpp->tpp_conn_orient /* Only dgram primary is *not* connection-oriented */ || !tport_is_primary(self) || !tport_is_dgram(self); n = tl_tgets(ta_args(ta), TPTAG_MTU(tpp->tpp_mtu), TPTAG_REUSE(self->tp_reusable), TPTAG_CONNECT(connect), TPTAG_QUEUESIZE(tpp->tpp_qsize), TPTAG_IDLE(tpp->tpp_idle), TPTAG_TIMEOUT(tpp->tpp_timeout), TPTAG_SDWN_ERROR(tpp->tpp_sdwn_error), TPTAG_DEBUG_DROP(tpp->tpp_drop), TPTAG_THRPSIZE(tpp->tpp_thrpsize), TPTAG_THRPRQSIZE(tpp->tpp_thrprqsize), TAG_IF(pri, TPTAG_PUBLIC(pri ? pri->pri_public : 0)), TAG_END()); ta_end(ta); return n;}/** Set transport parameters. * * @param self pointer to a transport object * @param tag,value,... list of tags */int tport_set_params(tport_t *self, tag_type_t tag, tag_value_t value, ...){ ta_list ta; int n; tport_params_t tpp[1], *tpp0; int connect, sdwn_error, reusable, stun_server; struct sigcomp_compartment *cc = NONE; if (self == NULL) return su_seterrno(EINVAL); memcpy(tpp, tpp0 = self->tp_params, sizeof *tpp); connect = tpp->tpp_conn_orient; sdwn_error = tpp->tpp_sdwn_error; reusable = self->tp_reusable; stun_server = tpp->tpp_stun_server; ta_start(ta, tag, value); n = tl_gets(ta_args(ta), TPTAG_MTU_REF(tpp->tpp_mtu), TAG_IF(!self->tp_queue, TPTAG_QUEUESIZE_REF(tpp->tpp_qsize)), TPTAG_IDLE_REF(tpp->tpp_idle), TPTAG_TIMEOUT_REF(tpp->tpp_timeout), TPTAG_DEBUG_DROP_REF(tpp->tpp_drop), TPTAG_THRPSIZE_REF(tpp->tpp_thrpsize), TPTAG_THRPRQSIZE_REF(tpp->tpp_thrprqsize), TPTAG_SIGCOMP_LIFETIME_REF(tpp->tpp_sigcomp_lifetime), TPTAG_CONNECT_REF(connect), TPTAG_SDWN_ERROR_REF(sdwn_error), TPTAG_REUSE_REF(reusable), TPTAG_COMPARTMENT_REF(cc), TPTAG_STUN_SERVER_REF(stun_server), TAG_END()); ta_end(ta); if (n == 0) return 0; if (tpp->tpp_idle > 0 && tpp->tpp_idle < 2000) tpp->tpp_idle = 2000; if (tpp->tpp_timeout < 1000) tpp->tpp_timeout = 1000; if (tpp->tpp_drop > 1000) tpp->tpp_drop = 1000; if (tpp->tpp_thrprqsize > 0) tpp->tpp_thrprqsize = tpp0->tpp_thrprqsize; if (tpp->tpp_sigcomp_lifetime != 0 && tpp->tpp_sigcomp_lifetime < 30) tpp->tpp_sigcomp_lifetime = 30; if (tpp->tpp_qsize >= 1000) tpp->tpp_qsize = 1000; /* Currently only primary UDP transport can *not* be connection oriented */ tpp->tpp_conn_orient = connect; tpp->tpp_sdwn_error = sdwn_error; self->tp_reusable = reusable; tpp->tpp_stun_server = stun_server; if (tport_is_secondary(self) && self->tp_params == self->tp_pri->pri_primary->tp_params) { tpp0 = su_zalloc(self->tp_home, sizeof *tpp0); if (!tpp0) return -1; } memcpy(tpp0, tpp, sizeof *tpp); return n;}extern tport_vtable_t const tport_udp_vtable;extern tport_vtable_t const tport_tcp_vtable;extern tport_vtable_t const tport_tls_vtable;extern tport_vtable_t const tport_sctp_vtable;extern tport_vtable_t const tport_udp_client_vtable;extern tport_vtable_t const tport_tcp_client_vtable;extern tport_vtable_t const tport_sctp_client_vtable;extern tport_vtable_t const tport_tls_client_vtable;extern tport_vtable_t const tport_http_connect_vtable;extern tport_vtable_t const tport_threadpool_vtable;#define TPORT_NUMBER_OF_TYPES 64tport_vtable_t const *tport_vtables[TPORT_NUMBER_OF_TYPES + 1] ={ &tport_http_connect_vtable,#if HAVE_TLS &tport_tls_client_vtable, &tport_tls_vtable,#endif#if HAVE_SCTP /* SCTP is broken */ &tport_sctp_client_vtable, &tport_sctp_vtable,#endif &tport_tcp_client_vtable, &tport_tcp_vtable, &tport_udp_client_vtable, &tport_udp_vtable,#if 0 &tport_threadpool_vtable,#endif#if HAVE_SOFIA_STUN &tport_stun_vtable,#endif};/** Register new transport vtable */int tport_register_type(tport_vtable_t const *vtp){ int i; for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) { if (tport_vtables[i] == NULL) { tport_vtables[i] = vtp; return 0; } } su_seterrno(ENOMEM); return -1;}/**Get a vtable for given protocol */tport_vtable_t const *tport_vtable_by_name(char const *protoname, enum tport_via public) { int i; for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) { tport_vtable_t const *vtable = tport_vtables[i]; if (vtable == NULL) continue; if (vtable->vtp_public != public) continue; if (strcasecmp(vtable->vtp_name, protoname)) continue; assert(vtable->vtp_pri_size >= sizeof (tport_primary_t)); assert(vtable->vtp_secondary_size >= sizeof (tport_t)); return vtable; } return NULL;}#if 0tport_set_f const *tport_set_methods[TPORT_NUMBER_OF_TYPES + 1] = { tport_server_bind_set, tport_client_bind_set, tport_threadpool_set, tport_http_connect_set,#if HAVE_TLS tport_tls_set,#endif NULL };int tport_bind_set(tport_master_t *mr, tp_name_t const *tpn, char const * const transports[], tagi_t const *taglist, tport_set_t **return_set, int set_size){ int i; for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) { tport_set_f const *perhaps = tport_vtables[i]; int result; if (perhaps == NULL) continue; result = perhaps(mr, tpn, transports, taglist, return_set, set_size); if (result != 0) return result; } return 0;}#endif/** Bind transport objects. * * @param self pointer to a transport object * @param tpn desired transport address * @param transports list of protocol names supported by stack * @param tag,value,... tagged argument list */int tport_tbind(tport_t *self, tp_name_t const *tpn, char const * const transports[], tag_type_t tag, tag_value_t value, ...){ ta_list ta; int server = 1, retval, public = 0; tp_name_t mytpn[1]; tport_master_t *mr; char const *http_connect = NULL; if (self == NULL || tport_is_secondary(self) || tpn == NULL || transports == NULL) { su_seterrno(EINVAL); return -1; } *mytpn = *tpn; if (mytpn->tpn_ident == NULL) mytpn->tpn_ident = self->tp_ident; ta_start(ta, tag, value); tl_gets(ta_args(ta), TPTAG_SERVER_REF(server), TPTAG_PUBLIC_REF(public), TPTAG_IDENT_REF(mytpn->tpn_ident), TPTAG_HTTP_CONNECT_REF(http_connect), TAG_END()); mr = self->tp_master; assert(mr); if (http_connect && public == 0) public = tport_type_connect; if (public && public != tport_type_stun) server = 0; if (server) retval = tport_bind_server(mr, mytpn, transports, public, ta_args(ta)); else retval = tport_bind_client(mr, mytpn, transports, public, ta_args(ta)); ta_end(ta); return retval;}/** Bind primary transport objects used by a client-only application. * @internal */int tport_bind_client(tport_master_t *mr, tp_name_t const *tpn, char const * const transports[], enum tport_via public, tagi_t *tags){ int i; tport_primary_t *pri = NULL, **tbf; tp_name_t tpn0[1] = {{ "*", "*", "*", "*", NULL, NULL }}; char const *why = "unknown"; tport_vtable_t const *vtable; if (public == tport_type_local) public = tport_type_client; SU_DEBUG_5(("%s(%p) to " TPN_FORMAT "\n", __func__, mr, TPN_ARGS(tpn))); memset(tpn0, 0, sizeof(tpn0)); for (tbf = &mr->mr_primaries; *tbf; tbf = &(*tbf)->pri_next) ; for (i = 0; transports[i]; i++) { su_addrinfo_t hints[1]; char const *proto = transports[i]; if (strcmp(proto, tpn->tpn_proto) != 0 && strcmp(tpn->tpn_proto, tpn_any) != 0) continue; vtable = tport_vtable_by_name(proto, public); if (!vtable) continue; /* Resolve protocol, skip unknown transport protocols */ if (getprotohints(hints, proto, AI_PASSIVE) < 0) continue; tpn0->tpn_proto = proto; tpn0->tpn_comp = tpn->tpn_comp; tpn0->tpn_ident = tpn->tpn_ident; hints->ai_canonname = "*"; if (!(pri = tport_alloc_primary(mr, vtable, tpn0, hints, tags, &why))) break; pri->pri_public = tport_type_client; /* XXX */ } if (!pri) { SU_DEBUG_3(("tport_alloc_primary: %s failed\n", why)); tport_zap_primary(*tbf); } return pri ? 0 : -1;}/** Bind primary transport objects used by a server application. */int tport_bind_server(tport_master_t *mr, tp_name_t const *tpn, char const * const transports[], enum tport_via public, tagi_t *tags){ char hostname[256]; char const *canon = NULL, *host, *service; int error = 0, not_supported, family = 0; tport_primary_t *pri = NULL, **tbf; su_addrinfo_t *ai, *res = NULL; unsigned port, port0, port1, old; unsigned short step = 0; bind6only_check(mr); SU_DEBUG_5(("%s(%p) to " TPN_FORMAT "\n", __func__, mr, TPN_ARGS(tpn))); if (tpn->tpn_host == NULL || strcmp(tpn->tpn_host, tpn_any) == 0) { /* Use a local IP address */ host = NULL; }#ifdef SU_HAVE_IN6 else if (tpn->tpn_host && tpn->tpn_host[0] == '[') { /* Remove [] around IPv6 addresses. */ host = strcpy(hostname, tpn->tpn_host + 1); hostname[strlen(hostname) - 1] = '\0'; }#endif else host = tpn->tpn_host; if (tpn->tpn_port != NULL && strlen(tpn->tpn_port) > 0 && strcmp(tpn->tpn_port, tpn_any) != 0) service = tpn->tpn_port; else service = ""; if (host && (strcmp(host, "0.0.0.0") == 0 || strcmp(host, "0") == 0)) host = NULL, family = AF_INET;#if SU_HAVE_IN6 else if (host && strcmp(host, "::") == 0) host = NULL, family = AF_INET6;#endif if (tpn->tpn_canon && strcmp(tpn->tpn_canon, tpn_any) && (host || tpn->tpn_canon != tpn->tpn_host)) canon = tpn->tpn_canon; if (tport_server_addrinfo(mr, canon, family, host, service, tpn->tpn_proto, transports, &res) < 0) return -1; for (tbf = &mr->mr_primaries; *tbf; tbf = &(*tbf)->pri_next) ; port = port0 = port1 = ntohs(((su_sockaddr_t *)res->ai_addr)->su_port); error = EPROTONOSUPPORT; /* * Loop until we can bind all the transports requested * by the transport user to the same port. */ for (;;) { for (ai = res; ai; ai = ai->ai_next) { tp_name_t tpname[1]; su_addrinfo_t ainfo[1]; su_sockaddr_t su[1]; tport_vtable_t const *vtable; vtable = tport_vtable_by_name(ai->ai_canonname, public); if (!vtable) continue; tport_addrinfo_copy(ainfo, su, sizeof su, ai); ainfo->ai_canonname = (char *)canon; su->su_port = htons(port); memcpy(tpname, tpn, sizeof tpname); tpname->tpn_canon = canon; tpname->tpn_host = host; SU_DEBUG_9(("%s(%p): calling tport_listen for %s\n", __func__, mr, ai->ai_canonname)); pri = tport_listen(mr, vtable, tpname, ainfo, tags); if (!pri) { switch (error = su_errno()) { case EADDRNOTAVAIL: /* Not our address */ case ENOPROTOOPT: /* Protocol not supported */ case ESOCKTNOSUPPORT: /* Socket type not supported */ continue; default: break; } break; } not_supported = 0; if (port0 == 0 && port == 0) { port = port1 = ntohs(su->su_port); assert(public != tport_type_server || port != 0); } } if (ai == NULL) break; while (*tbf) tport_zap_primary(*tbf); if (error != EADDRINUSE || port0 != 0 || port == 0) break; while (step == 0) { /* step should be relative prime to 65536 - 1024 */ /* 65536 - 1024 = 7 * 3 * 3 * 1024 */ step = su_randint(1, 65535 - 1024 - 1) | 1; if (step % 3 == 0) step = (step + 2) % (65536 - 1024); if (step % 7 == 0) step = (step + 2) % (65536 - 1024); } old = port; port += step; if (port >= 65536) port -= (65536 - 1024); if (port == port1) /* All ports in use! */ break; SU_DEBUG_3(("%s(%p): cannot bind all transports to port %u, trying %u\n", __func__, mr, old, port)); } tport_freeaddrinfo(res); if (!*tbf) { su_seterrno(error); return -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -