⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tport.c

📁 this is simple sip stack.
💻 C
📖 第 1 页 / 共 5 页
字号:
/** 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 + -