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

📄 stun.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
  if ((sd->sd_index =       su_root_register(sh->sh_root, wait, stun_tls_callback, (su_wakeup_arg_t *) sd, 0)) == -1) {    STUN_ERROR(errno, su_root_register);    return -1;  }  sd->sd_state = stun_tls_connecting;  /* Create and start timer for connect() timeout */  SU_DEBUG_3(("%s: creating timeout timer for connect()\n", __func__));  connect_timer = su_timer_create(su_root_task(sh->sh_root),				  STUN_TLS_CONNECT_TIMEOUT);  /* sd->sd_connect_timer = connect_timer; */  su_timer_set(connect_timer, stun_tls_connect_timer_cb, (su_wakeup_arg_t *) sd);  return 0;}#elseint stun_handle_request_shared_secret(stun_handle_t *sh){  return 0;}#endif /* HAVE_OPENSSL */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_discovery_init;  memcpy(req->sr_local_addr, sd->sd_bind_addr, sizeof(su_sockaddr_t));  /* Insert this request to the request queue */  if (sh->sh_requests)    x_insert(sh->sh_requests, req, sr);  else    sh->sh_requests = req;  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);  if (!x_is_inserted(req, sr) && !req->sr_next)    sh->sh_requests = NULL;  req->sr_handle = NULL;  req->sr_discovery = NULL;  /* memset(req->sr_destination, 0, sizeof(su_sockaddr_t)); */  if (req->sr_msg)    stun_free_message(req->sr_msg);  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;  enter;  /* 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);  }  su_home_zap(sh->sh_home);}/** Create wait object and register it to the handle callback */int assign_socket(stun_discovery_t *sd, su_socket_t s) {  stun_handle_t *sh = sd->sd_handle;  int events;  stun_discovery_t *tmp;  /* su_localinfo_t clientinfo[1]; */  su_sockaddr_t bind_addr;  socklen_t bind_len;  char ipaddr[SU_ADDRSIZE + 2] = { 0 };  su_sockaddr_t *sa;  int err;    su_wait_t wait[1] = { SU_WAIT_INIT };  enter;  if (s == -1) {    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;  /* set socket asynchronous */  if (su_setblocking(s, 0) < 0) {    STUN_ERROR(errno, su_setblocking);    su_close(s);    return -1;  }  /* xxx -- check if socket is already assigned to this root */  events = SU_WAIT_IN | SU_WAIT_ERR;  if (su_wait_create(wait, s, events) == -1) {    STUN_ERROR(su_errno(), su_wait_create);    return -1;  }  /* 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) {    STUN_ERROR(errno, su_root_register);    return -1;  }  SU_DEBUG_7(("%s: socket registered.\n", __func__));  bind_len = sizeof bind_addr;  sa = (void *) &bind_addr;  bind_len = sizeof bind_addr;  memset(sa, 0, sizeof(bind_addr));  /* if bound check the error */  err = getsockname(s, (struct sockaddr *) sa, &bind_len);  if (err < 0 && errno == SOCKET_ERROR) {    STUN_ERROR(errno, getsockname);    return -1;  }  /* Not bound - bind it */  if (sa->su_port == 0) {#if defined (__CYGWIN__)    get_localinfo(clientinfo);#endif    if ((err = bind(s, (struct sockaddr *) sa, bind_len)) < 0) {      STUN_ERROR(errno, bind);      SU_DEBUG_3(("%s: Error binding to %s:%u\n", __func__, 		  inet_ntop(sa->su_family, SU_ADDR(sa), 			    ipaddr, sizeof(ipaddr)),		  (unsigned) ntohs(sa->su_port)));      return -1;    }    /* bind_len = clientinfo->li_addrlen; */    /* clientinfo->li_addrlen = bind_len; */    sa->su_len = bind_len; /* ? */  }  memcpy(&sd->sd_bind_addr, &bind_addr, sizeof bind_addr);  if (getsockname(s, (struct sockaddr *) &bind_addr, &bind_len) != 0) {    STUN_ERROR(errno, getsockname);    return -1;  }  SU_DEBUG_3(("%s: local socket is bound to %s:%u\n", __func__,	      inet_ntop(bind_addr.su_family, SU_ADDR(&bind_addr), 			ipaddr, sizeof(ipaddr)),	      (unsigned) ntohs(bind_addr.su_port)));  return 0;}/** * Helper function needed by Cygwin builds. */#if defined (__CYGWIN__)static int get_localinfo(su_localinfo_t *clientinfo){  su_localinfo_t  hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}, *li, *res = NULL;  su_sockaddr_t *sa;  int i, error, found = 0;  char ipaddr[SU_ADDRSIZE + 2] = { 0 };  hints->li_family = AF_INET;  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 != AF_INET)	continue;            clientinfo->li_family = li->li_family;      clientinfo->li_addrlen = li->li_addrlen;            sa = clientinfo->li_addr;      memcpy(sa, li->li_addr, sizeof(su_sockaddr_t));      SU_DEBUG_3(("%s: local address found to be %s.\n",		  __func__, 		  inet_ntop(clientinfo->li_family, SU_ADDR(sa),			    ipaddr, sizeof(ipaddr))));      found = 1;      break;    }        if (!found) {      STUN_ERROR(error, su_getlocalinfo);      return -1;    }  }  else {    STUN_ERROR(error, su_getlocalinfo);    return -1;  }  if (res)    su_freelocalinfo(res);  return 0;}#endif/** Bind a socket using STUN client.  * * The function stun_bind() obtains a global address for a UDP socket using * a STUN server.  *  * @param ss       dpointer to a STUN client object (IN) * @param my_addr  public address for socket (IN/OUT) * @param addrlen  length of pub_addr (IN/OUT) * @param lifetime return value pointer to lifetime of  *                 binding, -1 if no STUN not used (OUT) * * @return * On success, zero is returned.  Upon error, -1 is returned, and @e errno is * set appropriately. *  * @ERRORS * @ERROR EFAULT          An invalid address is given as argument * @ERROR EPROTONOSUPPORT Not a UDP socket. * @ERROR EINVAL          The socket is already bound to an address. * @ERROR EACCESS   	  The address is protected, and the user is not  *                  	  the super-user. * @ERROR ENOTSOCK  	  Argument is a descriptor for a file, not a socket. * @ERROR EAGAIN          Operation in progress. Application should call  *                        stun_bind() again when there is data available on  *                        the socket. *  */int stun_handle_bind(stun_handle_t *sh,		     tag_type_t tag, tag_value_t value,		     ...){  su_socket_t s = -1;  stun_request_t *req = NULL;  stun_discovery_t *sd = NULL;  ta_list ta;  stun_action_t action = stun_action_binding_request;  int index;  enter;  if (sh == NULL)    return errno = EFAULT, -1;  ta_start(ta, tag, value);  tl_gets(ta_args(ta),	  STUNTAG_SOCKET_REF(s),	  TAG_END());  ta_end(ta);  sd = stun_discovery_create(sh, action);  if ((index = assign_socket(sd, s)) < 0)    return -1;  req = stun_request_create(sd);  if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0 ||      stun_send_binding_request(req, sh->sh_pri_addr) < 0) {    stun_discovery_destroy(sd);    stun_free_message(req->sr_msg);    return -1;  }  /* note: we always report success if bind() succeeds */  return 0;}/** Return local NATed address  * This function returns the local address seen from outside. * Note that the address is not valid until the event stun_clien_done is launched. */su_sockaddr_t *stun_discovery_get_address(stun_discovery_t *sd){  enter;  return sd->sd_addr_seen_outside;}stun_discovery_t *stun_discovery_create(stun_handle_t *sh,					stun_action_t action){  stun_discovery_t *sd = NULL;  enter;  sd = calloc(1, sizeof(stun_discovery_t));  sd->sd_action = action;  sd->sd_handle = sh;  sd->sd_lt_cur = 0;  sd->sd_lt = STUN_LIFETIME_EST;  sd->sd_lt_max = STUN_LIFETIME_MAX;  sd->sd_pri_info.ai_addrlen = 16;  sd->sd_pri_info.ai_addr = &sd->sd_pri_addr->su_sa;  /* Insert this action to the discovery queue */  if (sh->sh_discoveries)    x_insert(sh->sh_discoveries, sd, sd);  else    sh->sh_discoveries = sd;  return sd;}int stun_discovery_destroy(stun_discovery_t *sd){  stun_handle_t *sh;  enter;  if (!sd)    return errno = EFAULT, -1;  sh = sd->sd_handle;  /* if we are in the queue*/  if (x_is_inserted(sd, sd))    x_remove(sd, sd);  /* if we were the only one */  else if (!sd->sd_next)    sh->sh_discoveries = NULL;  sd->sd_prev = NULL;  sd->sd_next = NULL;  free(sd);  return 0;}int stun_handle_get_nattype(stun_handle_t *sh,			    tag_type_t tag, tag_value_t value,			    ...){  int err = 0, index = 0;  ta_list ta;  char const *server = NULL;  stun_request_t *req = NULL;  stun_discovery_t *sd = NULL;  su_sockaddr_t bind_addr;  su_socket_t s = -1;  socklen_t bind_len;  su_sockaddr_t *destination = NULL;  ta_start(ta, tag, value);  enter;  tl_gets(ta_args(ta),	  STUNTAG_SOCKET_REF(s),	  STUNTAG_SERVER_REF(server),	  TAG_END());  ta_end(ta);  bind_len = sizeof bind_addr;  if (s < 0)    return errno = EFAULT, -1;  sd = stun_discovery_create(sh, stun_action_get_nattype);  if ((index = assign_socket(sd, s)) < 0)    return errno = EFAULT, -1;  /* If no server given, use default address from stun_handle_create() */  if (!server) {    /* memcpy(&sd->sd_pri_info, &sh->sh_pri_info, sizeof(su_addrinfo_t)); */    memcpy(sd->sd_pri_addr, sh->sh_pri_addr, sizeof(su_sockaddr_t));  }  else {    err = stun_atoaddr(AF_INET, &sd->sd_pri_info, server);    memcpy(sd->sd_pri_addr, &sd->sd_pri_info.ai_addr, sizeof(su_sockaddr_t));  }  destination = (su_sockaddr_t *) sd->sd_pri_addr;  req = stun_request_create(sd);  if (stun_make_binding_req(sh, req, req->sr_msg, 			    STUNTAG_CHANGE_IP(0), 			    STUNTAG_CHANGE_PORT(0),			    TAG_END()) < 0)     return -1;  err = stun_send_binding_request(req, destination);  if (err < 0) {    stun_free_message(req->sr_msg);    return -1;  }  /* Same Public IP and port, Test III, server ip 0 or 1 should be     the same */  req = stun_request_create(sd);  if (stun_make_binding_req(sh, req, req->sr_msg, 			    STUNTAG_CHANGE_IP(0), 			    STUNTAG_CHANGE_PORT(1),			    TAG_END()) < 0)     return -1;  err = stun_send_binding_request(req, destination);  if (err < 0) {    stun_free_message(req->sr_msg);    return -1;  }  req = NULL;  req = stun_request_create(sd);  if (stun_make_binding_req(sh, req, req->sr_msg, 			    STUNTAG_CHANGE_IP(1), 			    STUNTAG_CHANGE_PORT(1),			    TAG_END()) < 0)     return -1;    err = stun_send_binding_request(req, destination);  if (err < 0) {    stun_free_message(req->sr_msg);  }  return err;}/******************************************************************** * Internal functions *******************************************************************/

⌨️ 快捷键说明

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