📄 tport.c
字号:
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); (void)hostname; SU_DEBUG_5(("%s(%p) to " TPN_FORMAT "\n", __func__, (void *)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__, (void *)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__, (void *)mr, old, port)); } tport_freeaddrinfo(res); if (!*tbf) { su_seterrno(error); return -1; } return 0;}/** Check if we can bind to IPv6 separately from IPv4 bind */staticint bind6only_check(tport_master_t *mr){ int retval = 0;#if SU_HAVE_IN6 su_sockaddr_t su[1], su4[1]; socklen_t sulen, su4len; int s6, s4; if (mr->mr_boundserver) return 0; s4 = su_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); s6 = su_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); memset(su, 0, sizeof *su); su->su_len = sulen = (sizeof su->su_sin6); su->su_family = AF_INET6; memset(su4, 0, sizeof *su4); su4->su_len = su4len = (sizeof su->su_sin); su4->su_family = AF_INET; if (bind(s6, &su->su_sa, sulen) < 0) ; else if (getsockname(s6, &su->su_sa, &sulen) < 0) ; else if ((su4->su_port = su->su_port) != 0 && bind(s4, &su4->su_sa, su4len) == 0) retval = 1; su_close(s6), su_close(s4); mr->mr_bindv6only = retval; mr->mr_boundserver = 1;#endif return retval;}/* Number of supported transports */#define TPORT_N (8)/** Return list of addrinfo structures matching to * canon/host/service/protocol */staticint tport_server_addrinfo(tport_master_t *mr, char const *canon, int family, char const *host, char const *service, char const *protocol, char const * const transports[], su_addrinfo_t **return_addrinfo){ int i, N; su_addrinfo_t hints[TPORT_N + 1]; *return_addrinfo = NULL; /* * Resolve all the transports requested by the protocol */ for (i = 0, N = 0; transports[i] && N < TPORT_N; i++) { su_addrinfo_t *ai = &hints[N]; if (strcasecmp(transports[i], protocol) != 0 && strcmp(protocol, tpn_any) != 0) continue; /* Resolve protocol, skip unknown transport protocols. */ if (getprotohints(ai, transports[i], AI_PASSIVE) < 0) continue; ai->ai_family = family; ai->ai_next = &hints[++N]; } if (N == 0) return su_seterrno(EPROTONOSUPPORT); if (transports[i] /* Too many protocols */) return su_seterrno(ENOMEM); hints[N - 1].ai_next = NULL; if (host) { int error = tport_getaddrinfo(host, service, hints, return_addrinfo); if (error || !*return_addrinfo) { SU_DEBUG_3(("%s(%p): su_getaddrinfo(%s, %s) for %s: %s\n", __func__, (void *)mr, host ? host : "\"\"", service, protocol, su_gai_strerror(error))); return su_seterrno(error != EAI_MEMORY ? ENOENT : ENOMEM); } return 0; } return tport_get_local_addrinfo(mr, service, hints, return_addrinfo);}/** Convert localinfo into addrinfo */staticinttport_get_local_addrinfo(tport_master_t *mr, char const *port, su_addrinfo_t const *hints, su_addrinfo_t **return_ai){ int error, family; su_localinfo_t lihints[1] = {{ 0 }}; su_localinfo_t *li, *li_result; su_addrinfo_t const *h; su_addrinfo_t *ai, **prev; su_sockaddr_t *su; unsigned long lport = 0; char *rest; prev = return_ai, *prev = NULL; if (port) { lport = strtoul(port, &rest, 10); if (lport >= 65536) { su_seterrno(EINVAL); return -1; } } family = hints->ai_family; for (h = hints->ai_next; h && family; h = h->ai_next) if (h->ai_family != family) family = 0; lihints->li_flags = 0; lihints->li_family = family; lihints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE | LI_SCOPE_HOST; error = su_getlocalinfo(lihints, &li_result); if (error) {#if SU_HAVE_IN6 SU_DEBUG_3(("%s(%p): su_getlocalinfo() for %s address: %s\n", __func__, (void *)mr, family == AF_INET6 ? "ip6" : family == AF_INET ? "ip4" : "ip", su_gli_strerror(error)));#else SU_DEBUG_3(("%s(%p): su_getlocalinfo() for %s address: %s\n", __func__, (void *)mr, family == AF_INET ? "ip4" : "ip", su_gli_strerror(error)));#endif su_seterrno(ENOENT); return -1; } for (li = li_result; li; li = li->li_next) { for (h = hints; h; h = h->ai_next) { if (h->ai_family && h->ai_family != li->li_family) continue; ai = calloc(1, sizeof *ai + li->li_addrlen); if (ai == NULL) break; *prev = ai, prev = &ai->ai_next; ai->ai_flags = AI_PASSIVE | TP_AI_ANY; ai->ai_family = li->li_family; ai->ai_socktype = h->ai_socktype; ai->ai_protocol = h->ai_protocol; ai->ai_canonname = h->ai_canonname; ai->ai_addr = memcpy(ai + 1, li->li_addr, ai->ai_addrlen = li->li_addrlen); su = (void *)ai->ai_addr; su->su_port = htons(lport); } } su_freelocalinfo(li_result); if (li) { tport_freeaddrinfo(*return_ai); su_seterrno(ENOMEM); return -1; } if (*return_ai == NULL) { su_seterrno(ENOENT); return -1; } return 0;}su_inline su_addrinfo_t *get_next_addrinfo(su_addrinfo_t **all);/** Translate address and service. * * This is a getaddrinfo() supporting multiple hints in a list. */int tport_getaddrinfo(char const *node, char const *service, su_addrinfo_t const *hints, su_addrinfo_t **res){ su_addrinfo_t const *h0; su_addrinfo_t *tbf, **prev; int error = EAI_SOCKTYPE; int i, N; su_addrinfo_t *all[TPORT_N + 1]; /* Lists for all supported transports */ su_addrinfo_t *results[TPORT_N + 1]; void *addr; int addrlen; *res = NULL; for (N = 0, h0 = hints; h0; h0 = h0->ai_next) { su_addrinfo_t h[1]; *h = *h0, h->ai_next = NULL, h->ai_canonname = NULL; error = su_getaddrinfo(node, service, h, &all[N]); results[N] = all[N]; if (error == EAI_SOCKTYPE) { SU_DEBUG_7(("%s(): su_getaddrinfo(%s, %s) for %s: %s\n", __func__, node ? node : "\"\"", service, h0->ai_canonname, su_gai_strerror(error))); continue; } if (error || !all[N]) break; N++; } if (h0) for (i = 0; i < N; i++) su_freeaddrinfo(all[i]); if (error) return error; /* Combine all the valid addrinfo structures to a single list */ prev = &tbf, tbf = NULL; for (;;) { su_addrinfo_t *ai = NULL, *ai0; for (i = 0, h0 = hints; i < N; i++, h0 = h0->ai_next) { if ((ai = get_next_addrinfo(&results[i]))) break; } if (i == N) break; assert(ai); addr = SU_ADDR((su_sockaddr_t *)ai->ai_addr); addrlen = SU_ADDRLEN((su_sockaddr_t *)ai->ai_addr); /* Copy all the addrinfo structures with same address to the list */ for (; i < N; i++, h0 = h0->ai_next) { while ((ai0 = get_next_addrinfo(&results[i]))) { void *a = SU_ADDR((su_sockaddr_t *)ai0->ai_addr); if (memcmp(addr, a, addrlen)) /* Different address */ break; results[i] = ai0->ai_next; ai = calloc(1, sizeof *ai + ai0->ai_addrlen); if (ai == NULL) goto error; *prev = memcpy(ai, ai0, sizeof *ai); prev = &ai->ai_next; *prev = NULL; ai->ai_addr = memcpy(ai + 1, ai0->ai_addr, ai0->ai_addrlen); ai->ai_canonname = h0->ai_canonname; } } } for (i = 0; i < N; i++) su_freeaddrinfo(all[i]); *res = tbf; return 0; error: for (i = 0; i < N; i++) su_freeaddrinfo(all[i]); tport_freeaddrinfo(tbf); return EAI_MEMORY;}su_inlinesu_addrinfo_t *get_next_addrinfo(su_addrinfo_t **all){ su_addrinfo_t *ai; while ((ai = *all)) { if (ai->ai_family == AF_INET) return ai;#if SU_HAVE_IN6 if (ai->ai_family == AF_INET6) return ai;#endif *all = ai->ai_next; } return ai;}staticvoid tport_freeaddrinfo(su_addrinfo_t *ai){ su_addrinfo_t *ai_next; while (ai) { ai_next = ai->ai_next; free(ai); ai = ai_next; }}staticint tport_addrinfo_copy(su_addrinfo_t *dst, void *addr, socklen_t addrlen, su_addrinfo_t const *src){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -