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

📄 stun.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
    req->sr_request_mask = bits;    /* compose header */  msg->stun_hdr.msg_type = BINDING_REQUEST;  msg->stun_hdr.msg_len = 0; /* actual len computed by				stun_send_message */  for (i = 0; i < 8; i++) {    msg->stun_hdr.tran_id[i] = (1 + rand() % RAND_MAX_16);  }     /* optional attributes:   * - Response Address   * - Change Request X   * - Username   * - Message-Integrity */  msg->stun_attr = NULL;  /* CHANGE_REQUEST */  p = &(msg->stun_attr);  if (chg_ip || chg_port) {    stun_attr_changerequest_t *attr_cr;    tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));    tmp->attr_type = CHANGE_REQUEST;    attr_cr = (stun_attr_changerequest_t *) malloc(sizeof(stun_attr_changerequest_t));    attr_cr->value =      (chg_ip ? STUN_CR_CHANGE_IP : 0) | (chg_port ? STUN_CR_CHANGE_PORT : 0);    tmp->pattr = attr_cr;    tmp->next = NULL;    *p = tmp; p = &(tmp->next);  }  /* USERNAME */  if (sh->sh_use_msgint &&      sh->sh_username.data &&       sh->sh_passwd.data) {    tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));    tmp->attr_type = USERNAME;    tmp->pattr = &sh->sh_username;    tmp->next = NULL;    *p = tmp; p = &(tmp->next);    /* dummy MESSAGE_INTEGRITY attribute, computed later */    tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));    tmp->attr_type = MESSAGE_INTEGRITY;    tmp->pattr = NULL;    tmp->next = NULL;    *p = tmp; p = &(tmp->next);  }  /* no buffer assigned yet */  msg->enc_buf.data = NULL;  msg->enc_buf.size = 0;  return 0;}int stun_process_response(stun_msg_t *msg){  enter;  /* parse msg first */  if (stun_parse_message(msg) < 0) {    SU_DEBUG_3(("%s: Error parsing response.\n", __func__));    return -1;  }  /* check message digest if exists */  switch (msg->stun_hdr.msg_type) {  case BINDING_RESPONSE:    if (stun_process_binding_response(msg) < 0)       return -1;    break;  case BINDING_ERROR_RESPONSE:    if (stun_process_error_response(msg) < 0)      return -1;    break;  default:    return -1;  }  return 0;}/** process binding response */int stun_process_binding_response(stun_msg_t *msg) {  /* currently not needed. */  return 0;}/** process binding error response *  Report error and return */int stun_process_error_response(stun_msg_t *msg){  stun_attr_t *attr;  stun_attr_errorcode_t *ec;  enter;  attr = stun_get_attr(msg->stun_attr, ERROR_CODE);  if (attr == NULL) {    perror("stun_process_error_response");    return -1;  }  ec = (stun_attr_errorcode_t *)attr->pattr;    SU_DEBUG_5(("%s: Received Binding Error Response:\n", __func__));  SU_DEBUG_5(("%s: Error: %d %s\n", __func__, ec->code, ec->phrase));  return 0;}int stun_handle_set_uname_pwd(stun_handle_t *sh,			      const char *uname,			      int len_uname,			      const char *pwd,			      int len_pwd){  enter;  sh->sh_username.data = (unsigned char *) malloc(len_uname);  memcpy(sh->sh_username.data, uname, len_uname);  sh->sh_username.size = len_uname;    sh->sh_passwd.data = (unsigned char *) malloc(len_pwd);  memcpy(sh->sh_passwd.data, pwd, len_pwd);  sh->sh_passwd.size = len_pwd;  sh->sh_use_msgint = 1; /* turn on message integrity ussage */    return 0;}  /* convert character address format to sockaddr_in */int stun_atoaddr(int ai_family,		 su_addrinfo_t *info,		 char const *in){  su_addrinfo_t *res = NULL, *ai, hints[1] = {{ 0 }};  char const *host;  char *port = NULL, tmp[SU_ADDRSIZE];  int err;  su_sockaddr_t *addr;  assert(info && in);  enter;  addr = (su_sockaddr_t *) info->ai_addr;  /* note: works only for IPv4 */  hints->ai_family = ai_family;  port = strstr(in, ":");  if (port == NULL) {    host = in;  }  else {    assert(port - in < strlen(in) + 1);    memcpy(tmp, in, port - in);    tmp[port - in] = 0;    host = tmp;    ++port;  }      if ((err = su_getaddrinfo(host, NULL, hints, &res)) != 0) {    STUN_ERROR(err, su_getaddrinfo);    return -1;  }  for (ai = res; ai; ai = ai->ai_next) {    if (ai->ai_family != AF_INET)      continue;    info->ai_flags = ai->ai_flags;    info->ai_family = ai->ai_family;    info->ai_socktype = ai->ai_socktype;    info->ai_protocol = ai->ai_protocol;    info->ai_addrlen = ai->ai_addrlen;    memcpy(&addr->su_sa, res->ai_addr, sizeof(struct sockaddr));    break;  }  if (port)     addr->su_port = htons(atoi(port));  else    addr->su_port = htons(STUN_DEFAULT_PORT);  if (res)    su_freeaddrinfo(res);  return err;}int stun_handle_get_lifetime(stun_handle_t *sh,			     tag_type_t tag, tag_value_t value,			     ...){  stun_request_t *req = NULL;  stun_discovery_t *sd = NULL;  ta_list ta;  int s = -1, err, index = 0;  char ipaddr[SU_ADDRSIZE + 2] = { 0 };  char const *server = NULL;  su_socket_t sockfdy;  socklen_t y_len;  su_sockaddr_t y_addr;  su_sockaddr_t *destination;  assert(sh);  enter;  ta_start(ta, tag, value);  tl_gets(ta_args(ta),	  STUNTAG_SOCKET_REF(s),	  STUNTAG_SERVER_REF(server),	  TAG_END());  sd = stun_discovery_create(sh, stun_action_get_lifetime);  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);  /* ci = &req->sr_localinfo; */  /* get local ip address */  /* get_localinfo(ci); */  /* initialize socket y */  sockfdy = socket(AF_INET, SOCK_DGRAM, 0);  /* set socket asynchronous */  if (su_setblocking(sockfdy, 0) < 0) {    STUN_ERROR(errno, su_setblocking);    su_close(sockfdy);    return errno = EFAULT, -1;  }  sd->sd_socket2 = sockfdy;  memset(&y_addr, 0, sizeof(y_addr));  memcpy(&y_addr, sd->sd_bind_addr, sizeof(y_addr));  y_addr.su_port = 0;  y_len = sizeof(y_addr);  if (bind(sockfdy, (struct sockaddr *) &y_addr, y_len) < 0) {    return -1;  }  if (getsockname(sockfdy, (struct sockaddr *) &y_addr, &y_len) < 0) {    STUN_ERROR(errno, getsockname);    return -1;  }  SU_DEBUG_3(("%s: socket y bound to %s:%u\n", __func__,	      inet_ntop(y_addr.su_family, SU_ADDR(&y_addr), ipaddr, sizeof(ipaddr)),	      (unsigned) ntohs(y_addr.su_port)));  req->sr_from_y = -1;  SU_DEBUG_1(("%s: determining binding life time, this may take a while.\n", __func__));  if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0)     return -1;  err = stun_send_binding_request(req, destination);  if (err < 0) {    stun_free_message(req->sr_msg);    return -1;  }  ta_end(ta);  return 0;}int stun_add_response_address(stun_msg_t *req, struct sockaddr_in *mapped_addr){  stun_attr_sockaddr_t *addr;  stun_attr_t *tmp;  enter;  tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));  tmp->attr_type = RESPONSE_ADDRESS;  addr = malloc(sizeof(stun_attr_sockaddr_t));  memcpy(addr, mapped_addr, sizeof(stun_attr_sockaddr_t));  tmp->pattr = addr;    if (req->stun_attr == NULL) {    tmp->next = NULL;  }  else {    tmp->next = req->stun_attr;  }  req->stun_attr = tmp;  return 0;}/** Determine if the message is STUN message (0 if not). */int stun_msg_is_keepalive(uint16_t data){  uint16_t msg_type;  /* parse header */  msg_type = ntohs(data);  if (msg_type == BINDING_REQUEST ||      msg_type == BINDING_RESPONSE ||      msg_type == BINDING_ERROR_RESPONSE) {    return 0;  }  return -1;}/** Determine length of STUN message (0 if not stun). */int stun_message_length(void *data, int len, int end_of_message){  unsigned char *p;  uint16_t tmp16, msg_type;  /* parse header first */  p = data;  memcpy(&tmp16, p, 2);  msg_type = ntohs(tmp16);  if (msg_type == BINDING_REQUEST ||      msg_type == BINDING_RESPONSE ||      msg_type == BINDING_ERROR_RESPONSE) {    p+=2;    memcpy(&tmp16, p, 2);    /* return message length */    return ntohs(tmp16);  }  else    return -1;}/** Process incoming message */int stun_handle_process_message(stun_handle_t *sh, su_socket_t s, 				su_sockaddr_t *sa, socklen_t salen,				void *data, int len){  int retval = -1, err = -1, dgram_len;  char ipaddr[SU_ADDRSIZE + 2];  stun_msg_t msg;  unsigned char dgram[20] = { 0 };  su_sockaddr_t recv;  socklen_t recv_len;  enter;  /* Message received. */  msg.enc_buf.data = data;  msg.enc_buf.size = len;   debug_print(&msg.enc_buf);        /* Parse here the incoming message. */  if (stun_parse_message(&msg) < 0) {    stun_free_message(&msg);    SU_DEBUG_5(("%s: Error parsing response.\n", __func__));    return retval;  }  if (msg.stun_hdr.msg_type == BINDING_REQUEST) {    return stun_process_request(s, &msg, 0, sa, salen);  }  else if (msg.stun_hdr.msg_type == BINDING_RESPONSE) {    /* Based on the decoded payload, find the corresponding request     * (based on TID). */    return do_action(sh, &msg);  }  return -1;}/** Unregister socket from STUN handle event loop */int stun_handle_release(stun_handle_t *sh, su_socket_t s){  stun_discovery_t *sd;  assert (sh);  enter;  if (s < 0)    return errno = EFAULT, -1;  /* 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; sd = sd->sd_next) {    if (sd->sd_socket != s)      continue;    su_root_deregister(sh->sh_root, sd->sd_index);    sd->sd_index = -1; /* mark index as deregistered */    SU_DEBUG_3(("%s: socket deregistered from STUN \n", __func__));    return 0;  }  /* Oops, user passed wrong socket */  SU_DEBUG_3(("%s: socket given is not associated with STUN \n", __func__));  return -1;}/** stun_keepalive won't do su_root_register() */int stun_keepalive(stun_handle_t *sh,		   su_sockaddr_t *sa,		   tag_type_t tag, tag_value_t value,		   ...){  int s = -1;  unsigned int timeout = 0;  ta_list ta;  stun_discovery_t *sd;  stun_request_t *req;  stun_action_t action = stun_action_keepalive;  char ipaddr[SU_ADDRSIZE + 2] = { 0 };  enter;  ta_start(ta, tag, value);  tl_gets(ta_args(ta),	  STUNTAG_SOCKET_REF(s),	  STUNTAG_TIMEOUT_REF(timeout),	  TAG_END());  if (s < 1 || !sa || timeout == 0)    return errno = EFAULT, -1;  /* If there already is keepalive associated with the given socket,   * destroy it. */  stun_keepalive_destroy(sh, s);    /*Ok, here we go */  sd = stun_discovery_create(sh, action);  sd->sd_socket = s;  sd->sd_timeout = timeout;  memcpy(sd->sd_pri_addr, sa, sizeof(*sa));  req = stun_request_create(sd);  SU_DEBUG_3(("%s: Starting to send STUN keepalives to %s:%u\n", __func__, 	      inet_ntop(sa->su_family, SU_ADDR(sa), 			ipaddr, sizeof(ipaddr)),	      (unsigned) ntohs(sa->su_port)));    if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0 ||      stun_send_binding_request(req, sa) < 0) {    stun_request_destroy(req);    stun_discovery_destroy(sd);    return -1;  }    sd->sd_timer = su_timer_create(su_root_task(sh->sh_root), timeout);  su_timer_set(sd->sd_timer, stun_keepalive_timer_cb, (su_wakeup_arg_t *) sd);  ta_end(ta);  return 0;}/** Send SIP keepalives */void stun_keepalive_timer_cb(su_root_magic_t *magic, 			     su_timer_t *t,			     su_timer_arg_t *arg){  stun_discovery_t *sd = arg;  stun_handle_t *sh = sd->sd_handle;  int timeout = sd->sd_timeout;  su_sockaddr_t *destination = sd->sd_pri_addr;  stun_request_

⌨️ 快捷键说明

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