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

📄 stun.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
  su_sockaddr_t *clnt_addr = clnt_info->li_addr;  stun_msg_t *binding_request;  stun_discovery_t *sd = req->sr_discovery;  enter;  binding_request = req->sr_msg;  switch (binding_response->stun_hdr.msg_type) {  case BINDING_RESPONSE:    if (stun_validate_message_integrity(binding_response, &self->sh_passwd) < 0) {      stun_free_message(binding_request);      stun_free_message(binding_response);      return retval;    }    memset(clnt_addr, 0, sizeof(struct sockaddr_in));    clnt_addr_len = sizeof(su_sockaddr_t);    mapped_addr = stun_get_attr(binding_response->stun_attr, MAPPED_ADDRESS);    if (mapped_addr != NULL) {      memcpy(clnt_addr, mapped_addr->pattr, clnt_addr_len);      retval = 0;    }    /* update alternative server address */    if (sd->sd_sec_addr->su_family == 0) {      /* alternative server address not present */      chg_addr = stun_get_attr(binding_response->stun_attr, CHANGED_ADDRESS);      if (chg_addr != NULL)	memcpy(sd->sd_sec_addr, chg_addr->pattr, sizeof(struct sockaddr_in));    }    break;      case BINDING_ERROR_RESPONSE:  default:    if (stun_process_error_response(binding_response) < 0) {      SU_DEBUG_3(("%s: Error in Binding Error Response.\n", __func__));    }    req->sr_state = stun_bind_error;          break;  }  return retval;}void stun_get_lifetime_timer_cb(su_root_magic_t *magic, 				su_timer_t *t,				su_timer_arg_t *arg){  stun_request_t *req = arg;  stun_discovery_t *sd = req->sr_discovery;  su_sockaddr_t *destination;  int err;  enter;  su_timer_destroy(t);  destination = (su_sockaddr_t *) sd->sd_pri_addr;  err = stun_send_binding_request(req, destination);  if (err < 0) {    stun_free_message(req->sr_msg);    return;  }  return;}int process_get_lifetime(stun_request_t *req, stun_msg_t *binding_response){  stun_discovery_t *sd = req->sr_discovery;  stun_request_t *new;  stun_handle_t *sh = req->sr_handle;  su_localinfo_t *li;  su_sockaddr_t *sa;  su_timer_t *sockfdy_timer = NULL;  su_socket_t sockfdy = sd->sd_socket2;  int err;  stun_action_t action = get_action(req);  su_sockaddr_t *destination;  /* Even the first message could not be delivered */  if ((req->sr_state == stun_request_timeout) && (req->sr_from_y == -1)) {    SU_DEBUG_0(("%s: lifetime determination failed.\n", __func__));    sd->sd_state = stun_discovery_timeout;    sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);    req->sr_state = stun_dispose_me;    return 0;  }  if (abs(sd->sd_lt_cur - sd->sd_lt) <= STUN_LIFETIME_CI) {    sd->sd_state = stun_discovery_done;    sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);    req->sr_state = stun_dispose_me;    return 0;  }  /* We come here as a response to a request send from the sockfdy */  if (req->sr_from_y == 1) {    req->sr_state = stun_dispose_me, req = NULL;    new = stun_request_create(sd);    new->sr_from_y = 0;    if (stun_make_binding_req(sh, new, new->sr_msg, 0, 0) < 0)       return -1;    destination = (su_sockaddr_t *) sd->sd_pri_addr;    err = stun_send_binding_request(new, destination);    if (err < 0) {      stun_free_message(new->sr_msg);      return -1;    }    return 0;  }  else if (req->sr_from_y == 0) {    if (req->sr_state != stun_discovery_timeout) {      /* mapping with X still valid */      sd->sd_lt_cur = sd->sd_lt;      sd->sd_lt = (int) (sd->sd_lt + sd->sd_lt_max) / 2;      SU_DEBUG_1(("%s: Response received from socket X, " \		  "lifetime at least %d sec, next trial: %d sec\n",		  __func__, sd->sd_lt_cur, sd->sd_lt));    }    else {      sd->sd_lt_max = sd->sd_lt;      sd->sd_lt = (int) (sd->sd_lt + sd->sd_lt_cur) / 2;      SU_DEBUG_1(("%s: No response received from socket X, " \		  "lifetime at most %d sec, next trial: %d sec\n",		  __func__, sd->sd_lt_max, sd->sd_lt));    }  }  /* Rock, we come from sockfdx */  process_binding_request(req, binding_response);  li = &req->sr_localinfo;  sa = req->sr_local_addr;  stun_free_message(binding_response);    /* Destroy me with the bad mofo timer */  req->sr_state = stun_dispose_me, req = NULL;    new = stun_request_create(sd);  /* Use sockfdy */  new->sr_socket = sockfdy;  new->sr_from_y = 1;  if (stun_make_binding_req(sh, new, new->sr_msg, 0, 0) < 0)     return -1;  stun_add_response_address(new->sr_msg, (struct sockaddr_in *) sa);  /* Create and start timer */  sockfdy_timer = su_timer_create(su_root_task(sh->sh_root), sd->sd_lt);  su_timer_set(sockfdy_timer, stun_get_lifetime_timer_cb, (su_wakeup_arg_t *) new);  return 0;}int action_bind(stun_request_t *req, stun_msg_t *binding_response){  su_localinfo_t *li = NULL;  su_sockaddr_t *sa = NULL;  stun_discovery_t *sd = req->sr_discovery;  stun_handle_t *sh = req->sr_handle;  stun_action_t action;  enter;  action = get_action(req);  process_binding_request(req, binding_response);  li = &req->sr_localinfo;  sa = req->sr_local_addr;  memcpy(sd->sd_addr_seen_outside, sa, sizeof(su_sockaddr_t));  sd->sd_state = stun_bind_done;  sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);  req->sr_state = stun_dispose_me;  return 0;}int action_determine_nattype(stun_request_t *req, stun_msg_t *binding_response){  su_sockaddr_t local;  socklen_t locallen;  stun_handle_t *sh = req->sr_handle;  su_localinfo_t *li = NULL;  stun_discovery_t *sd = req->sr_discovery;  su_socket_t s = sd->sd_socket;  stun_action_t action;  int err;  enter;  action = get_action(req);  /* If the NAT type is already detected, ignore this request */  if (!sd || (sd->sd_nattype != stun_nat_unknown)) {    req->sr_state = stun_dispose_me;    /* stun_request_destroy(req); */    return 0;  }  /* parse first the payload */  if (binding_response)    process_binding_request(req, binding_response);  /* mapped address */  li = &req->sr_localinfo;  if (req->sr_request_mask == 0) {    sd->sd_first = 1;    memcpy(sd->sd_addr_seen_outside, li->li_addr, sizeof(su_sockaddr_t));  }  else if (req->sr_request_mask & (CHG_IP | CHG_PORT))    sd->sd_second = 1;  else if (req->sr_request_mask & CHG_PORT)    sd->sd_third = 1;  memset(&local, 0, sizeof(local));  locallen = sizeof(local);  err = getsockname(s, (struct sockaddr *) &local, &locallen);  if (err < 0)    STUN_ERROR(err, getsockname);  if ((req->sr_state == stun_discovery_timeout)) {    if (sd->sd_first && sd->sd_second && sd->sd_third && sd->sd_fourth) {	  sd->sd_nattype = stun_nat_port_res_cone;	  sd->sd_state = stun_discovery_done;	  sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);	  req->sr_state = stun_dispose_me;	  /* stun_request_destroy(req); */	  /* stun_discovery_destroy(sd); */	  return 0;    }    else if (sd->sd_first && sd->sd_second && sd->sd_fourth) {      /* Sudden network problem */      sd->sd_nattype = stun_nat_unknown;      sd->sd_state = stun_discovery_done;      sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);      req->sr_state = stun_dispose_me;      /* stun_request_destroy(req); */      /* stun_discovery_destroy(sd); */      return 0;    }    else if (sd->sd_first && sd->sd_second) {      if (memcmp(li->li_addr, li->li_addr, 8) == 0) {	sd->sd_nattype = stun_sym_udp_fw;	sd->sd_state = stun_discovery_done;	sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);	req->sr_state = stun_dispose_me;	/* stun_request_destroy(req); */	/* stun_discovery_destroy(sd); */	return 0;      }      else {	sd->sd_fourth = 1;	/* The request will be destroyed by the timer */	req->sr_state = stun_dispose_me;	req = NULL;	req = stun_request_create(sd);	if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0) 	  return -1;	err = stun_send_binding_request(req, sd->sd_sec_addr);	if (err < 0) {	  stun_free_message(req->sr_msg);	  return -1;	}	return 0;      }    }    else if (sd->sd_first) {      sd->sd_nattype = stun_udp_blocked;      sd->sd_state = stun_discovery_done;      sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);      req->sr_state = stun_dispose_me;      /* stun_request_destroy(req); */      /* stun_discovery_destroy(sd); */      return 0;    }  }  else {    if (sd->sd_first && sd->sd_second && sd->sd_third && sd->sd_fourth) {      if (memcmp(li->li_addr, sd->sd_addr_seen_outside, 8) == 0) {	/* Response: Type 6 - Restricted */	sd->sd_nattype = stun_nat_res_cone;      }      else {	sd->sd_nattype = stun_nat_sym;      }      sd->sd_state = stun_discovery_done;      sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);      req->sr_state = stun_dispose_me;      /* stun_request_destroy(req); */      /* stun_discovery_destroy(sd); */      return 0;    }    if (sd->sd_first && sd->sd_second) {      if (memcmp(li->li_addr, sd->sd_addr_seen_outside, 8) == 0)	sd->sd_nattype = stun_open_internet;      else	sd->sd_nattype = stun_nat_full_cone;      sd->sd_state = stun_discovery_done;      sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);      req->sr_state = stun_dispose_me;      /* stun_request_destroy(req); */      /* stun_discovery_destroy(sd); */      return 0;    }    else if (sd->sd_first) {      if (memcmp(&local, li->li_addr, 8) == 0)	return 0;    }  }  /* The discovery process is still ongoing, but I can be killed */  req->sr_state = stun_dispose_me;  return 0;}void stun_sendto_timer_cb(su_root_magic_t *magic, 			  su_timer_t *t,			  su_timer_arg_t *arg){  stun_request_t *req = arg;  stun_handle_t *sh = req->sr_handle;  stun_discovery_t *sd = req->sr_discovery;  stun_action_t action = get_action(req);  long timeout = 0;  enter;  if (req->sr_state == stun_dispose_me) {    su_timer_destroy(t);    stun_request_destroy(req);    SU_DEBUG_7(("%s: timer destroyed.\n", __func__));    return;  }  ++req->sr_retry_count;  /* check if max retry count has been exceeded */  if (req->sr_retry_count >= sh->sh_max_retries) {    errno = ETIMEDOUT;    STUN_ERROR(errno, stun_sendto_timer_cb);    stun_free_message(req->sr_msg);    free(req->sr_msg), req->sr_msg = NULL;    /* Either the server was dead, address wrong or STUN_UDP_BLOCKED */    /* sd->sd_nattype = stun_udp_blocked; */    req->sr_state = stun_request_timeout;    /* If the action is binding request, we are done. If action was       NAT type determination, process with the state machine. */    switch (action) {    case stun_action_binding_request:      sd->sd_state = stun_discovery_timeout;      sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);      req->sr_state = stun_dispose_me;      break;    case stun_action_get_nattype:      action_determine_nattype(req, NULL);      break;          case stun_action_get_lifetime:      process_get_lifetime(req, NULL);      break;          case stun_action_keepalive:      sd->sd_state = stun_discovery_timeout;      sh->sh_callback(sh->sh_context, sh, req, sd, action, sd->sd_state);      stun_keepalive_destroy(sh, sd->sd_socket);            break;    default:      break;            return;    }    /* Destroy me immediately */    req->sr_state = stun_dispose_me;    timeout = 0;  }  else {    SU_DEBUG_3(("%s: Timeout no. %d, retransmitting.\n",		__func__, req->sr_retry_count));        /* Use pre-defined destination address for re-sends */    if (stun_send_message(req->sr_socket, req->sr_destination,			  req->sr_msg, &(sh->sh_passwd)) < 0) {      stun_free_message(req->sr_msg);      free(req->sr_msg), req->sr_msg = NULL;      return;    }    timeout = req->sr_timeout *= 2;  }    su_timer_set_at(t, stun_sendto_timer_cb, (su_wakeup_arg_t *) req,		  su_time_add(su_now(), timeout));    return;}/** This function sends a binding request to the address at serv (ip, *  port). which could be the original or alternative socket addresses *  of the STUN server. Local address is provided in cli, and *  resulting mapped address is also saved in cli. *  Return 0 if successful, -1 if failed * * @return * On success, zero is returned.  Upon error, -1 is returned, and @e errno is * set appropriately. *  * @ERRORS * @ERROR EBADF           @a sockfd is not a valid deseriptor. * @ERROR EPROTONOSUPPORT @a sockfd is not an 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. * @ERROR ETIMEDOUT       Request timed out. *  */   int stun_send_binding_request(stun_request_t *req,			      su_sockaddr_t  *srvr_addr){  su_timer_t *sendto_timer = NULL;  int s;  stun_handle_t *sh = req->sr_handle;  stun_msg_t *msg =  req->sr_msg;  assert (sh && srvr_addr);  enter;  s = req->sr_socket;  memcpy(req->sr_destination, srvr_addr, sizeof(su_sockaddr_t));  if (stun_send_message(s, srvr_addr, msg, &(sh->sh_passwd)) < 0) {    return -1;  }  /* Create and start timer */  sendto_timer = su_timer_create(su_root_task(sh->sh_root), STUN_SENDTO_TIMEOUT);  su_timer_set(sendto_timer, stun_sendto_timer_cb, (su_wakeup_arg_t *) req);  req->sr_state = stun_discovery_processing;  return 0;}/** Compose a STUN message of the format defined by stun_msg_t */int stun_make_binding_req(stun_handle_t *sh,			  stun_request_t *req,			  stun_msg_t *msg,			  tag_type_t tag, tag_value_t value, ...){  int i;  stun_attr_t *tmp, **p;   int bits = 0;  int chg_ip = 0, chg_port = 0;   ta_list ta;  enter;  ta_start(ta, tag, value);  tl_gets(ta_args(ta),	  STUNTAG_CHANGE_IP_REF(chg_ip),	  STUNTAG_CHANGE_PORT_REF(chg_port),	  TAG_END());  ta_end(ta);    if (chg_ip)    bits |= CHG_IP;  if (chg_port)    bits |= CHG_PORT;  if (req)

⌨️ 快捷键说明

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