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

📄 tport.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 5 页
字号:
  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 + -