📄 tport.c
字号:
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 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); s6 = 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__, 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__, 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__, 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;}static 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;}static 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){ if (addrlen < src->ai_addrlen) return -1; memcpy(dst, src, sizeof *dst); if (src->ai_addrlen < addrlen) memset(addr, 0, addrlen); dst->ai_addr = memcpy(addr, src->ai_addr, src->ai_addrlen); dst->ai_next = NULL; return 0;}/** Close a transport. * * The function tport_close() closes a socket associated with a transport * object. */void tport_close(tport_t *self){ int i; SU_DEBUG_5(("%s(%p): " TPN_FORMAT "\n", "tport_close", self, TPN_ARGS(self->tp_name))); self->tp_closed = 1; self->tp_send_close = 3; self->tp_recv_close = 3; if (self->tp_params->tpp_sdwn_error && self->tp_pused) tport_error_report(self, -1, NULL); if (self->tp_pri->pri_vtable->vtp_shutdown) self->tp_pri->pri_vtable->vtp_shutdown(self, 2); else if (self->tp_socket != -1) shutdown(self->tp_socket, 2); if (self->tp_index) su_root_deregister(self->tp_master->mr_root, self->tp_index); self->tp_index = 0;#if SU_HAVE_BSDSOCK if (self->tp_socket != -1) su_close(self->tp_socket); self->tp_socket = -1;#endif /* Zap the queued messages */ if (self->tp_queue) { int N = self->tp_params->tpp_qsize; for (i = 0; i < N; i++) { if (self->tp_queue[i]) msg_ref_destroy(self->tp_queue[i]), self->tp_queue[i] = NULL; } } self->tp_index = 0; self->tp_events = 0;}/** Shutdown a transport. * * The tport_shutdown() shuts down a full-duplex transport connection * partially or completely. If @a how is 0, the further incoming data is * shut down. If @a how is 1, further outgoing data is shut down. If @a how * is 2, both incoming and outgoing traffic is shut down. * */int tport_shutdown(tport_t *self, int how){ if (!tport_is_secondary(self)) return -1; SU_DEBUG_7(("%s(%p, %d)\n", "tport_shutdown", self, how)); if (!tport_is_tcp(self) || how < 0 || (how == 0 && self->tp_send_close) || (how == 1 && self->tp_recv_close > 1) || how >= 2) { tport_close(self); return 1; } if (self->tp_pri->pri_vtable->vtp_shutdown) self->tp_pri->pri_vtable->vtp_shutdown(self, how); else shutdown(self->tp_socket, how); if (how == 0) { self->tp_recv_close = 2; tport_set_events(self, 0, SU_WAIT_IN); if (self->tp_params->tpp_sdwn_error && self->tp_pused) tport_error_report(self, -1, NULL); } else if (how == 1) { self->tp_send_close = 2; tport_set_events(self, 0, SU_WAIT_OUT); if (self->tp_queue && self->tp_queue[self->tp_qhead]) { int i, N = self->tp_params->tpp_qsize; for (i = 0; i < N; i++) { if (self->tp_queue[i]) { tport_pending_errmsg(self, self->tp_queue[i], EPIPE); msg_ref_destroy(self->tp_queue[i]), self->tp_queue[i] = NULL; } } } } return 0;}static inlineunsigned long tport_now(void){ return su_now().tv_sec;}/** Transport timer function. */staticvoid tport_tick(su_root_magic_t *magic, su_timer_t *t, tport_master_t *mr){ tport_primary_t *dad; tport_t *tp, *tp_next; su_time_t now = su_now(); int ts = su_time_ms(now); /* Go through all primary transports */ for (dad = mr->mr_primaries; dad; dad = dad->pri_next) { if (dad->pri_primary->tp_addrinfo->ai_protocol == IPPROTO_SCTP) { /* Go through all SCTP connections */ tp = dad->pri_secondary; for (tp = tprb_first(tp); tp; tp = tp_next) { tp_next = tprb_succ(tp); if (tp->tp_queue && tp->tp_queue[tp->tp_qhead]) { SU_DEBUG_9(("tport_tick(%p) - trying to send to %s/%s:%s\n", tp, tp->tp_protoname, tp->tp_host, tp->tp_port)); tport_send_queue(tp); } } } /* Go through all secondary transports with incomplete messages */ for (tp = tprb_first(dad->pri_secondary); tp; tp = tp_next) { msg_t *msg = tp->tp_msg; int closed; if (msg && tp->tp_params->tpp_timeout != UINT_MAX && tp->tp_params->tpp_timeout < ts - (int)tp->tp_time && !msg_is_streaming(msg)) { SU_DEBUG_5(("tport_tick(%p): incomplete message idle for %d ms\n", tp, ts - (int)tp->tp_time)); msg_set_streaming(msg, 0); msg_set_flags(msg, MSG_FLG_ERROR | MSG_FLG_TRUNC | MSG_FLG_TIMEOUT); tport_deliver(tp, msg, NULL, NULL, now); tp->tp_msg = NULL; } tp_next = tprb_succ(tp); if (tp->tp_refs) continue; closed = tport_is_closed(tp); if (!closed && !(tp->tp_params->tpp_idle > 0 && tp->tp_params->tpp_idle < ts - (int)tp->tp_time)) { continue; } if (closed) { SU_DEBUG_5(("tport_tick(%p): closed, zapping\n", tp)); } else { SU_DEBUG_5(("tport_tick(%p): unused for %d ms, closing and zapping\n", tp, ts - (int)tp->tp_time)); if (!tport_is_closed(tp)) tport_close(tp); } tport_zap_secondary(tp); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -