📄 tport.c
字号:
mr->mr_master->tp_reusable = 1; tpp->tpp_mtu = UINT_MAX; tpp->tpp_thrprqsize = THRP_PENDING; tpp->tpp_qsize = TPORT_QUEUESIZE; tpp->tpp_sdwn_error = 1; tpp->tpp_idle = UINT_MAX; tpp->tpp_timeout = UINT_MAX; tpp->tpp_sigcomp_lifetime = UINT_MAX; tpp->tpp_keepalive = 0; tpp->tpp_pingpong = 0; tpp->tpp_pong2ping = 0; tpp->tpp_stun_server = 1; tpp->tpp_tos = -1; /* set invalid, valid values are 0-255 */ tpn = mr->mr_master->tp_name; tpn->tpn_proto = "*"; tpn->tpn_host = "*"; tpn->tpn_canon = "*"; tpn->tpn_port = "*"; ta_start(ta, tag, value); tport_set_params(mr->mr_master, ta_tags(ta));#if HAVE_SOFIA_STUN tport_init_stun_server(mr, ta_args(ta));#endif ta_end(ta); return mr->mr_master;}/** Destroy the master transport. */void tport_destroy(tport_t *self){ tport_master_t *mr; static tp_stack_class_t tport_destroy_tpac[1] = {{ sizeof tport_destroy_tpac, /* tpac_recv */ tport_destroy_recv, /* tpac_error */ tport_destroy_error, /* tpac_alloc */ tport_destroy_alloc, /* tpac_address */ NULL }}; SU_DEBUG_7(("%s(%p)\n", __func__, (void *)self)); if (self == NULL) return; assert(tport_is_master(self)); if (!tport_is_master(self)) return; mr = (tport_master_t *)self; mr->mr_tpac = tport_destroy_tpac; while (mr->mr_primaries) tport_zap_primary(mr->mr_primaries);#if HAVE_SOFIA_STUN tport_deinit_stun_server(mr);#endif if (mr->mr_dump_file) fclose(mr->mr_dump_file), mr->mr_dump_file = NULL; if (mr->mr_timer) su_timer_destroy(mr->mr_timer), mr->mr_timer = NULL; su_home_zap(mr->mr_home);}/** Allocate a primary transport */static tport_primary_t *tport_alloc_primary(tport_master_t *mr, tport_vtable_t const *vtable, tp_name_t tpn[1], su_addrinfo_t *ai, tagi_t const *tags, char const **return_culprit){ tport_primary_t *pri, **next; tport_t *tp; int save_errno; for (next = &mr->mr_primaries; *next; next = &(*next)->pri_next) ; assert(vtable->vtp_pri_size >= sizeof *pri); if ((pri = su_home_clone(mr->mr_home, vtable->vtp_pri_size))) { tport_t *tp = pri->pri_primary; pri->pri_vtable = vtable; pri->pri_public = vtable->vtp_public; tp->tp_master = mr; tp->tp_pri = pri; tp->tp_socket = INVALID_SOCKET; tp->tp_magic = mr->mr_master->tp_magic; tp->tp_params = pri->pri_params; memcpy(tp->tp_params, mr->mr_params, sizeof (*tp->tp_params)); tp->tp_reusable = mr->mr_master->tp_reusable; if (!pri->pri_public) tp->tp_addrinfo->ai_addr = &tp->tp_addr->su_sa; SU_DEBUG_5(("%s(%p): new primary tport %p\n", __func__, (void *)mr, (void *)pri)); } *next = pri; tp = pri->pri_primary; if (!tp) *return_culprit = "alloc"; else if (tport_set_params(tp, TAG_NEXT(tags)) < 0) *return_culprit = "tport_set_params"; else if (vtable->vtp_init_primary && vtable->vtp_init_primary(pri, tpn, ai, tags, return_culprit) < 0) ; else if (tport_setname(tp, vtable->vtp_name, ai, tpn->tpn_canon) == -1) *return_culprit = "tport_setname"; else if (tpn->tpn_ident && !(tp->tp_name->tpn_ident = su_strdup(tp->tp_home, tpn->tpn_ident))) *return_culprit = "alloc ident"; else return pri; /* Success */ save_errno = su_errno(); tport_zap_primary(pri); su_seterrno(save_errno); return NULL;}/** Destroy a primary transport and its secondary transports. @internal */static void tport_zap_primary(tport_primary_t *pri){ tport_primary_t **prip; if (pri == NULL) return; assert(tport_is_primary(pri->pri_primary)); if (pri->pri_vtable->vtp_deinit_primary) pri->pri_vtable->vtp_deinit_primary(pri); while (pri->pri_open) tport_zap_secondary(pri->pri_open); while (pri->pri_closed) tport_zap_secondary(pri->pri_closed); /* We have just a single-linked list for primary transports */ for (prip = &pri->pri_master->mr_primaries; *prip != pri; prip = &(*prip)->pri_next) assert(*prip); *prip = pri->pri_next; tport_zap_secondary((tport_t *)pri);}/**Create a primary transport object with socket. * * Creates a primary transport object with a server socket, and then * registers the socket with suitable events to the root. * * @param dad parent (master or primary) transport object * @param ai pointer to addrinfo structure * @param canon canonical name of node * @param protoname name of the protocol */statictport_primary_t *tport_listen(tport_master_t *mr, tport_vtable_t const *vtable, tp_name_t tpn[1], su_addrinfo_t *ai, tagi_t *tags){ tport_primary_t *pri = NULL; int err; int errlevel = 3; char buf[TPORT_HOSTPORTSIZE]; char const *protoname = vtable->vtp_name; char const *culprit = "unknown"; su_sockaddr_t *su = (void *)ai->ai_addr; /* Log an error, return error */#define TPORT_LISTEN_ERROR(errno, what) \ ((void)(err = errno, \ ((err == EADDRINUSE || err == EAFNOSUPPORT || \ err == ESOCKTNOSUPPORT || err == EPROTONOSUPPORT || \ err == ENOPROTOOPT ? 7 : 3) < SU_LOG_LEVEL ? \ su_llog(tport_log, errlevel, \ "%s(%p): %s(pf=%d %s/%s): %s\n", \ __func__, pri ? (void *)pri : (void *)mr, what, \ ai->ai_family, protoname, \ tport_hostport(buf, sizeof(buf), su, 2), \ su_strerror(err)) : (void)0), \ tport_zap_primary(pri), \ su_seterrno(err)), \ (void *)NULL) /* Create a primary transport object for another transport. */ pri = tport_alloc_primary(mr, vtable, tpn, ai, tags, &culprit); if (pri == NULL) return TPORT_LISTEN_ERROR(errno, culprit); if (pri->pri_primary->tp_socket != INVALID_SOCKET) { int index = 0; tport_t *tp = pri->pri_primary; su_wait_t wait[1] = { SU_WAIT_INIT }; if (su_wait_create(wait, tp->tp_socket, tp->tp_events) == -1) return TPORT_LISTEN_ERROR(su_errno(), "su_wait_create"); /* Register receiving or accepting function with events specified above */ index = su_root_register(mr->mr_root, wait, tport_wakeup_pri, tp, 0); if (index == -1) { su_wait_destroy(wait); return TPORT_LISTEN_ERROR(su_errno(), "su_root_register"); } tp->tp_index = index; } pri->pri_primary->tp_has_connection = 0; SU_DEBUG_5(("%s(%p): %s " TPN_FORMAT "\n", __func__, (void *)pri, "listening at", TPN_ARGS(pri->pri_primary->tp_name))); return pri;}int tport_bind_socket(int socket, su_addrinfo_t *ai, char const **return_culprit){ su_sockaddr_t *su = (su_sockaddr_t *)ai->ai_addr; socklen_t sulen = (socklen_t)(ai->ai_addrlen); if (bind(socket, ai->ai_addr, sulen) == -1) { return *return_culprit = "bind", -1; } if (getsockname(socket, &su->su_sa, &sulen) == SOCKET_ERROR) { return *return_culprit = "getsockname", -1; } ai->ai_addrlen = sulen;#if defined (__linux__) && defined (SU_HAVE_IN6) if (ai->ai_family == AF_INET6) { if (!SU_SOCKADDR_INADDR_ANY(su) && (IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr) || IN6_IS_ADDR_V4COMPAT(&su->su_sin6.sin6_addr))) { su_sockaddr_t su0[1]; memcpy(su0, su, sizeof su0); memset(su, 0, ai->ai_addrlen = sizeof su->su_sin); su->su_family = ai->ai_family = AF_INET; su->su_port = su0->su_port; #ifndef IN6_V4MAPPED_TO_INADDR#define IN6_V4MAPPED_TO_INADDR(in6, in4) \ memcpy((in4), 12 + (uint8_t *)(in6), sizeof(struct in_addr))#endif IN6_V4MAPPED_TO_INADDR(&su0->su_sin6.sin6_addr, &su->su_sin.sin_addr); } }#endif return 0;}/** Indicate stack that a transport has been updated */void tport_has_been_updated(tport_t *self){ self->tp_pri->pri_updating = 0; if (self->tp_master->mr_tpac->tpac_address) self->tp_master->mr_tpac->tpac_address(self->tp_master->mr_stack, self);}staticint tport_set_events(tport_t *self, int set, int clear){ int events; if (self == NULL) return -1; events = (self->tp_events | set) & ~clear; self->tp_events = events; if (self->tp_pri->pri_vtable->vtp_set_events) return self->tp_pri->pri_vtable->vtp_set_events(self); SU_DEBUG_7(("tport_set_events(%p): events%s%s%s\n", (void *)self, (events & SU_WAIT_IN) ? " IN" : "", (events & SU_WAIT_OUT) ? " OUT" : "", SU_WAIT_CONNECT != SU_WAIT_OUT && (events & SU_WAIT_CONNECT) ? " CONNECT" : "")); return su_root_eventmask(self->tp_master->mr_root, self->tp_index, self->tp_socket, self->tp_events = events);}/**Allocate a secondary transport. @internal * * Create a secondary transport object. The new transport initally shares * parameters structure with the original transport. * * @param pri primary transport * @param socket socket for transport * @parma accepted true if the socket was accepted from server socket * * @return * Pointer to the newly created transport, or NULL upon an error. * * @note The socket is always closed upon error. */tport_t *tport_alloc_secondary(tport_primary_t *pri, int socket, int accepted, char const **return_reason){ tport_master_t *mr = pri->pri_master; tport_t *self; self = su_home_clone(mr->mr_home, pri->pri_vtable->vtp_secondary_size); if (self) { SU_DEBUG_7(("%s(%p): new secondary tport %p\n", __func__, (void *)pri, (void *)self)); self->tp_refs = -1; /* Freshly allocated */ self->tp_master = mr; self->tp_pri = pri; self->tp_params = pri->pri_params; self->tp_accepted = accepted != 0; self->tp_reusable = pri->pri_primary->tp_reusable; self->tp_magic = pri->pri_primary->tp_magic; self->tp_addrinfo->ai_addr = (void *)self->tp_addr; self->tp_socket = socket; self->tp_timer = su_timer_create(su_root_task(mr->mr_root), 0); self->tp_stime = self->tp_ktime = self->tp_rtime = su_now(); if (pri->pri_vtable->vtp_init_secondary && pri->pri_vtable->vtp_init_secondary(self, socket, accepted, return_reason) < 0) { if (pri->pri_vtable->vtp_deinit_secondary) pri->pri_vtable->vtp_deinit_secondary(self); su_home_zap(self->tp_home); return NULL; } /* Set IP TOS if it is set in primary */ tport_set_tos(socket, pri->pri_primary->tp_addrinfo, pri->pri_params->tpp_tos); } else { su_close(socket); *return_reason = "malloc"; } return self;}/** Create a connected transport object with socket. * * The function tport_connect() creates a secondary transport with a * connected socket. It registers the socket with suitable events to the * root. * * @param pri primary transport object * @param ai pointer to addrinfo structure * @param tpn canonical name of node */statictport_t *tport_connect(tport_primary_t *pri, su_addrinfo_t *ai, tp_name_t const *tpn){ tport_t *tp; if (ai == NULL || ai->ai_addrlen > sizeof (pri->pri_primary->tp_addr)) return NULL; if (pri->pri_vtable->vtp_connect) return pri->pri_vtable->vtp_connect(pri, ai, tpn); tp = tport_base_connect(pri, ai, ai, tpn); if (tp) tport_set_secondary_timer(tp); return tp;}/**Create a connected transport object with socket. * * The function tport_connect() creates a secondary transport with a * connected socket. It registers the socket with suitable events to the * root. * * @param pri primary transport object * @param ai pointer to addrinfo structure describing socket * @param real_ai pointer to addrinfo structure describing real target * @param tpn canonical name of node */tport_t *tport_base_connect(tport_primary_t *pri, su_addrinfo_t *ai, su_addrinfo_t *real_ai, tp_name_t const *tpn){ tport_master_t *mr = pri->pri_master; tport_t *self = NULL; su_socket_t s, server_socket; su_wait_t wait[1] = { SU_WAIT_INIT }; su_wakeup_f wakeup = tport_wakeup; int index = 0; int events = SU_WAIT_IN | SU_WAIT_ERR; int err; unsigned errlevel = 3; char buf[TPORT_HOSTPORTSIZE]; char const *what; /* Log an error, return error */#define TPORT_CONNECT_ERROR(errno, what) \ return \ ((void)(err = errno, \ su_wait_destroy(wait), \ (SU_LOG_LEVEL >= errlevel ? \ su_llog(tport_log, errlevel, \ "%s(%p): %s(pf=%d %s/%s): %s\n", \ __func__, (void *)pri, #what, ai->ai_family, \ tpn->tpn_proto, \ tport_hostport(buf, sizeof(buf), \ (void *)ai->ai_addr, 2), \ su_strerror(err)) : (void)0), \ tport_zap_secondary(self), \ su_seterrno(err)), \ (void *)NULL) s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (s == INVALID_SOCKET) TPORT_CONNECT_ERROR(su_errno(), "socket"); what = "tport_alloc_secondary"; if ((self = tport_alloc_secondary(pri, s, 0, &what)) == NULL) TPORT_CONNECT_ERROR(errno, what); self->tp_conn_orient = 1; if ((server_socket = pri->pri_primary->tp_socket) != INVALID_SOCKET) { su_sockaddr_t susa; socklen_t susalen = sizeof(susa); /* Bind this socket to same IP address as the primary server socket */ if (getsockname(server_socket, &susa.su_sa, &susalen) < 0) { SU_DEBUG_3(("%s(%p): getsockname(): %s\n", __func__, (void *)self, su_strerror(su_errno()))); } else { susa.su_port = 0; if (bind(s, &susa.su_sa, susalen) < 0) { SU_DEBUG_3(("%s(%p): bind(local-ip): %s\n", __func__, (void *)self, su_strerror(su_errno()))); } } } /* Set sockname for the tport */ if (tport_setname(self, tpn->tpn_proto, real_ai, tpn->tpn_canon) == -1) TPORT_CONNECT_ERROR(su_errno(), tport_setname); /* Try to have a non-blocking connect(). * The su_wait_create() below makes the socket non-blocking anyway. */ su_setblocking(s, 0); if (connect(s, ai->ai_addr, (socklen_t)(ai->ai_addrlen)) == SOCKET_ERROR) { err = su_errno();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -