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

📄 stun.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 5 页
字号:
    return NULL;  }    stun->sh_pri_info.ai_addrlen = 16;  stun->sh_pri_info.ai_addr = &stun->sh_pri_addr->su_sa;  stun->sh_sec_info.ai_addrlen = 16;  stun->sh_sec_info.ai_addr = &stun->sh_sec_addr->su_sa;  stun->sh_localinfo.li_addrlen = 16;  stun->sh_localinfo.li_addr = stun->sh_local_addr;  stun->sh_domain = su_strdup(stun->sh_home, domain);  stun->sh_dns_lookup = NULL;    if (server) {    err = stun_atoaddr(stun->sh_home, AF_INET, &stun->sh_pri_info, server);    if (err < 0) {      errno = ENOENT;      return NULL;    }  }  stun->sh_nattype = stun_nat_unknown;  stun->sh_root     = root;  /* always try TLS: */  stun->sh_use_msgint = 1;  /* whether use of shared-secret msgint is required */  stun->sh_req_msgint = req_msg_integrity;  stun->sh_max_retries = STUN_MAX_RETRX;  /* initialize username and password */  stun_init_buffer(&stun->sh_username);  stun_init_buffer(&stun->sh_passwd);    stun->sh_nattype = stun_nat_unknown;    /* initialize random number generator */  srand(time(NULL));   return stun;}/**  * Performs shared secret request/response processing. * Result will be trigged in STUN handle callback (state * one of stun_tls_*). **/int stun_obtain_shared_secret(stun_handle_t *sh,			      stun_discovery_f sdf,			      stun_discovery_magic_t *magic,			      tag_type_t tag, tag_value_t value, ...){#if HAVE_OPENSSL  int events = -1;  int one, err = -1;  su_wait_t wait[1] = { SU_WAIT_INIT };  su_socket_t s = INVALID_SOCKET;  int family;  su_addrinfo_t *ai = NULL;  stun_discovery_t *sd;  /* stun_request_t *req; */  ta_list ta;  assert(sh);  enter;  if (!sh->sh_pri_addr[0].su_port) {    /* no STUN server address, perform a DNS-SRV lookup */       ta_list ta;    ta_start(ta, tag, value);    SU_DEBUG_5(("Delaying STUN shared-secret req. for DNS-SRV query.\n"));    err = priv_dns_queue_action(sh, stun_action_tls_query, sdf, magic, ta_tags(ta));    ta_end(ta);           return err;  }  ai = &sh->sh_pri_info;  if (sh->sh_use_msgint == 1) {    SU_DEBUG_3(("%s: Obtaining shared secret.\n", __func__));  }  else {    SU_DEBUG_3(("No message integrity enabled.\n"));    return errno = EFAULT, -1;  }  /* open tcp connection to server */  s = su_socket(family = AF_INET, SOCK_STREAM, 0);  if (s == INVALID_SOCKET) {    return STUN_ERROR(errno, socket);  }  /* asynchronous connect() */  if (su_setblocking(s, 0) < 0) {    return STUN_ERROR(errno, su_setblocking);  }  if (setsockopt(s, SOL_TCP, TCP_NODELAY,		 (void *)&one, sizeof one) == -1) {    return STUN_ERROR(errno, setsockopt);  }  /* Do an asynchronous connect(). Three error codes are ok,   * others cause return -1. */  if (connect(s, (struct sockaddr *) &sh->sh_pri_addr, 	      ai->ai_addrlen) == SOCKET_ERROR) {    err = su_errno();    if (err != EINPROGRESS && err != EAGAIN && err != EWOULDBLOCK) {      return STUN_ERROR(err, connect);    }  }  SU_DEBUG_9(("%s: %s: %s\n", __func__, "connect",	      su_strerror(err)));    sd = stun_discovery_create(sh, stun_action_tls_query, sdf, magic);  sd->sd_socket = s;  /* req = stun_request_create(sd); */  events = SU_WAIT_CONNECT | SU_WAIT_ERR;  if (su_wait_create(wait, s, events) == -1)    return STUN_ERROR(errno, su_wait_create);  /* su_root_eventmask(sh->sh_root, sh->sh_root_index, s, events); */  if ((sd->sd_index =       su_root_register(sh->sh_root, wait, stun_tls_callback, (su_wakeup_arg_t *) sd, 0)) == -1) {    return STUN_ERROR(errno, su_root_register);  }  ta_start(ta, tag, value);  sd->sd_tags = tl_adup(sh->sh_home, ta_args(ta));  ta_end(ta);  sd->sd_state = stun_tls_connecting;  /* Create and start timer for connect() timeout */  SU_DEBUG_3(("%s: creating timeout timer for connect()\n", __func__));  sd->sd_timer = su_timer_create(su_root_task(sh->sh_root),				 STUN_TLS_CONNECT_TIMEOUT);  su_timer_set(sd->sd_timer, stun_tls_connect_timer_cb, (su_wakeup_arg_t *) sd);  return 0;#else /* !HAVE_OPENSSL */  return -1;#endif}static stun_request_t *stun_request_create(stun_discovery_t *sd){  stun_handle_t *sh = sd->sd_handle;  stun_request_t *req = NULL;  enter;  req = calloc(sizeof(stun_request_t), 1);  if (!req)    return NULL;  req->sr_handle = sh;  req->sr_discovery = sd;  /* This is the default */  req->sr_socket = sd->sd_socket;    req->sr_localinfo.li_addrlen = sizeof(su_sockaddr_t);  req->sr_localinfo.li_addr = req->sr_local_addr;    /* default timeout for next sendto() */  req->sr_timeout = STUN_SENDTO_TIMEOUT;  req->sr_retry_count = 0;  /* req->sr_action = action; */  req->sr_request_mask = 0;    req->sr_msg = calloc(sizeof(stun_msg_t), 1);  req->sr_state = stun_req_discovery_init;  memcpy(req->sr_local_addr, sd->sd_bind_addr, sizeof(su_sockaddr_t));  /* Insert this request to the request queue */  x_insert(sh->sh_requests, req, sr);  return req;}void stun_request_destroy(stun_request_t *req){  stun_handle_t *sh;  assert(req);  enter;  sh = req->sr_handle;  if (x_is_inserted(req, sr))    x_remove(req, sr);  req->sr_handle = NULL;  req->sr_discovery = NULL;  /* memset(req->sr_destination, 0, sizeof(su_sockaddr_t)); */  if (req->sr_timer) {    su_timer_destroy(req->sr_timer);    req->sr_timer = NULL;    SU_DEBUG_7(("%s: timer destroyed.\n", __func__));  }  if (req->sr_msg) {    free(req->sr_msg);    req->sr_msg = NULL;  }  free(req);  SU_DEBUG_9(("%s: request destroyed.\n", __func__));  return;}/** Destroy a STUN client */ void stun_handle_destroy(stun_handle_t *sh){   stun_discovery_t *sd = NULL, *kill = NULL;  stun_request_t *a, *b;  enter;  if (sh->sh_dns_lookup)    stun_dns_lookup_destroy(sh->sh_dns_lookup);  if (sh->sh_dns_pend_tags)    su_free(sh->sh_home, sh->sh_dns_pend_tags);  for (a = sh->sh_requests; a; ) {    b = a->sr_next;    stun_request_destroy(a);    a = b;  }  /* There can be several discoveries using the same socket. It is     still enough to deregister the socket in first of them */  for (sd = sh->sh_discoveries; sd; ) {    kill = sd;    sd = sd->sd_next;    /* Index has same value as sockfd, right? ... or not? */    if (kill->sd_index != -1)      su_root_deregister(sh->sh_root, kill->sd_index);    if (kill->sd_action == stun_action_tls_query)      su_close(kill->sd_socket);    stun_discovery_destroy(kill);  }  stun_free_message(&sh->sh_tls_request);  stun_free_message(&sh->sh_tls_response);  stun_free_buffer(&sh->sh_username);  stun_free_buffer(&sh->sh_passwd);  su_home_zap(sh->sh_home);}/** Create wait object and register it to the handle callback */staticint assign_socket(stun_discovery_t *sd, su_socket_t s, int register_socket) {  stun_handle_t *sh = sd->sd_handle;  int events;  stun_discovery_t *tmp;  /* su_localinfo_t clientinfo[1]; */  su_sockaddr_t su[1];  socklen_t sulen;  char addr[SU_ADDRSIZE];  int err;    su_wait_t wait[1] = { SU_WAIT_INIT };  enter;  if (s == INVALID_SOCKET) {    SU_DEBUG_3(("%s: invalid socket\n", __func__));    return errno = EINVAL, -1;  }  for (tmp = sh->sh_discoveries; tmp; tmp = tmp->sd_next) {    if (tmp->sd_socket == s) {      sd->sd_socket = s;      sd->sd_index = tmp->sd_index;      memcpy(sd->sd_bind_addr, tmp->sd_bind_addr, sizeof(su_sockaddr_t));      return 0;    }  }  sd->sd_socket = s;  if (!register_socket)    return 0;  /* set socket asynchronous */  if (su_setblocking(s, 0) < 0) {    return STUN_ERROR(errno, su_setblocking);  }  /* xxx -- check if socket is already assigned to this root */  memset(su, 0, sulen = sizeof su);  /* Try to bind it if not already bound */  if (getsockname(s, &su->su_sa, &sulen) == -1 || su->su_port == 0) {    sulen = su->su_len = sizeof su->su_sin;    su->su_family = AF_INET;#if defined (__CYGWIN__)    get_localinfo(AF_INET, su, &sulen);#endif    if ((err = bind(s, &su->su_sa, sulen)) < 0) {      SU_DEBUG_3(("%s: bind(%s:%u): %s\n",  __func__, 		  su_inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),		  (unsigned) ntohs(su->su_port),		  su_strerror(su_errno())));      return -1;    }    if (getsockname(s, &su->su_sa, &sulen) == -1) {      return STUN_ERROR(errno, getsockname);    }  }  memcpy(&sd->sd_bind_addr, su, sulen);  SU_DEBUG_3(("%s: local socket is bound to %s:%u\n", __func__,	      su_inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),	      (unsigned) ntohs(su->su_port)));  events = SU_WAIT_IN | SU_WAIT_ERR;  if (su_wait_create(wait, s, events) == -1) {    return STUN_ERROR(su_errno(), su_wait_create);  }  /* Register receiving function with events specified above */  if ((sd->sd_index = su_root_register(sh->sh_root,				       wait, stun_bind_callback,				       (su_wakeup_arg_t *) sd, 0)) < 0) {    return STUN_ERROR(errno, su_root_register);  }  SU_DEBUG_7(("%s: socket registered.\n", __func__));  return 0;}/** * Helper function needed by Cygwin builds. */#if defined (__CYGWIN__)static int get_localinfo(int family, su_sockaddr_t *su, socklen_t *return_len){  su_localinfo_t hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}, *li, *res = NULL;  int i, error;  char addr[SU_ADDRSIZE];  hints->li_family = family;  if ((error = su_getlocalinfo(hints, &res)) == 0) {    /* try to bind to the first available address */    for (i = 0, li = res; li; li = li->li_next) {      if (li->li_family != family)	continue;      if (li->li_scope == LI_SCOPE_HOST)	continue;      assert(*return_len >= li->li_addrlen);      memcpy(su, li->li_addr, *return_len = li->li_addrlen);      SU_DEBUG_3(("%s: using local address %s\n", __func__, 		  su_inet_ntop(family, SU_ADDR(su), addr, sizeof(addr))));      break;    }    su_freelocalinfo(res);        if (!li) {			/* Not found */      return STUN_ERROR(error, su_getlocalinfo);    }    return 0;  }  else {    return STUN_ERROR(error, su_getlocalinfo);  }}#endifstatic void priv_lookup_cb(stun_dns_lookup_t *self,			   stun_magic_t *magic){  const char *udp_target = NULL;  uint16_t udp_port = 0;  int res;  stun_handle_t *sh = (stun_handle_t *)magic;  res = stun_dns_lookup_udp_addr(self, &udp_target, &udp_port);  if (res == 0 && udp_target) {    /* XXX: assumption that same host and port used for UDP/TLS */    stun_atoaddr(sh->sh_home, AF_INET, &sh->sh_pri_info, udp_target);        if (udp_port)       sh->sh_pri_addr[0].su_port = htons(udp_port);    else      sh->sh_pri_addr[0].su_port = htons(STUN_DEFAULT_PORT);    /* step: now that server address is known, continue      *       the pending action */    SU_DEBUG_5(("STUN server address found, running queue actions (%d).\n",		sh->sh_dns_pend_action));    switch(sh->sh_dns_pend_action) {    case stun_action_tls_query:      stun_obtain_shared_secret(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));      break;    case stun_action_binding_request:      stun_bind(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));      break;          case stun_action_test_lifetime:      stun_test_lifetime(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));      break;          case stun_action_test_nattype:      stun_test_nattype(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));      break;          default:      SU_DEBUG_5(("Warning: unknown pending STUN DNS-SRV action.\n"));    }      }  else {    /* DNS lookup failed */    SU_DEBUG_5(("Warning: STUN DNS-SRV lookup failed.\n"));    if (sh->sh_dns_pend_cb) {      sh->sh_dns_pend_cb(sh->sh_dns_pend_ctx, sh, NULL,			 sh->sh_dns_pend_action, stun_error);    }  }  su_free(sh->sh_home, sh->sh_dns_pend_tags), sh->sh_dns_pend_tags = NULL;  sh->sh_dns_pend_action = 0;  sh->sh_dns_pend_cb = NULL;  sh->sh_dns_pend_ctx = NULL;}/** * Queus a discovery process for later execution when DNS-SRV lookup * has been completed. */static int priv_dns_queue_action(stun_handle_t *sh,				 stun_action_t action,				 stun_discovery_f sdf,				 stun_discovery_magic_t *magic,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -