Exemplo n.º 1
0
Arquivo: turn.c Projeto: roxlu/krx_rtc
size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg,
    uint8_t *buffer, size_t buffer_len,
    StunMessage *previous_response, int32_t lifetime,
    uint8_t *username, size_t username_len,
    uint8_t *password, size_t password_len,
    StunUsageTurnCompatibility compatibility)
{

  if (compatibility != STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 &&
      compatibility != STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
    return stun_usage_turn_create (agent, msg, buffer, buffer_len,
        previous_response, STUN_USAGE_TURN_REQUEST_PORT_NORMAL, 0, lifetime,
        username, username_len, password, password_len, compatibility);
  }

  stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_REFRESH);
  if (lifetime >= 0) {
    if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) !=
        STUN_MESSAGE_RETURN_SUCCESS)
      return 0;
  }

  if (previous_response) {
    uint8_t *realm;
    uint8_t *nonce;
    uint16_t len;

    realm = (uint8_t *) stun_message_find (previous_response,
        STUN_ATTRIBUTE_REALM, &len);
    if (realm != NULL) {
      if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) !=
          STUN_MESSAGE_RETURN_SUCCESS)
        return 0;
    }
    nonce = (uint8_t *) stun_message_find (previous_response,
        STUN_ATTRIBUTE_NONCE, &len);
    if (nonce != NULL) {
      if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) !=
          STUN_MESSAGE_RETURN_SUCCESS)
        return 0;
    }
  }


  if (username != NULL && username_len > 0) {
    if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
            username, username_len) != STUN_MESSAGE_RETURN_SUCCESS)
      return 0;
  }


  return stun_agent_finish_message (agent, msg, password, password_len);
}
Exemplo n.º 2
0
/** Various responses test */
static void test_turn (char *username, char *password, char *hostname, int port)
{
  struct sockaddr_storage addr;
  socklen_t addrlen = sizeof (addr);
  struct sockaddr_storage alternate_addr;
  socklen_t alternate_addrlen = sizeof (alternate_addr);
  struct sockaddr_storage relay_addr;
  socklen_t relay_addrlen = sizeof (relay_addr);
  ssize_t val;
  size_t len;
  int fd;
  uint8_t buf[STUN_MAX_MESSAGE_SIZE];
  uint8_t req[STUN_MAX_MESSAGE_SIZE];
  uint8_t refresh[STUN_MAX_MESSAGE_SIZE];
  size_t req_len;
  StunAgent agent;
  StunMessage msg;
  StunMessage req_msg;
  StunMessage refresh_msg;
  uint32_t bandwidth, lifetime;
  struct addrinfo hints, *res;
  int ret = -1;

  memset (&hints, 0, sizeof (hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_flags = 0;

  ret = getaddrinfo (hostname, port, &hints, &res);
  assert (ret == 0);

  stun_agent_init (&agent, STUN_ALL_KNOWN_ATTRIBUTES,
      STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS);

  /* Allocate a client socket and connect to server */
  fd = socket (AF_INET, SOCK_DGRAM, 0);
  assert (fd != -1);

  val = connect (fd,res->ai_addr, res->ai_addrlen);
#ifdef G_OS_WIN32
  assert (val == 0 || (WSAGetLastError () == WSAEINPROGRESS));
#else
  assert (val == 0 || (errno == EINPROGRESS));
#endif

  freeaddrinfo (res);


  /* Send old-style response */
  req_len = stun_usage_turn_create (&agent, &req_msg, req, sizeof(req),
      NULL,
      STUN_USAGE_TURN_REQUEST_PORT_NORMAL,
      -1, -1,
      username, strlen (username), password, strlen(password),
      STUN_USAGE_TURN_COMPATIBILITY_DRAFT9);
  assert (req_len > 0);

  val = send (fd, req, req_len, MSG_NOSIGNAL);
  assert (val >= 0);

  val = recv (fd, buf, 1000, 0);
  assert (val >= 0);

  assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL)
      == STUN_VALIDATION_SUCCESS);

  val = stun_usage_turn_process (&msg,
      (struct sockaddr *)&relay_addr, &relay_addrlen,
      (struct sockaddr *)&addr, &addrlen,
      (struct sockaddr *)&alternate_addr, &alternate_addrlen,
      &bandwidth, &lifetime,
      STUN_USAGE_TURN_COMPATIBILITY_DRAFT9);
  assert (val == STUN_USAGE_TURN_RETURN_ERROR);

  req_len = stun_usage_turn_create (&agent, &req_msg, req, sizeof(req),
      &msg,
      STUN_USAGE_TURN_REQUEST_PORT_NORMAL,
      -1, -1,
      username, strlen (username), password, strlen(password),
      STUN_USAGE_TURN_COMPATIBILITY_DRAFT9);
  assert (req_len > 0);

  val = send (fd, req, req_len, MSG_NOSIGNAL);
  assert (val >= 0);

  val = recv (fd, buf, 1000, 0);
  assert (val >= 0);

  assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL)
      == STUN_VALIDATION_SUCCESS);

  val = stun_usage_turn_process (&msg,
      (struct sockaddr *)&relay_addr, &relay_addrlen,
      (struct sockaddr *)&addr, &addrlen,
      (struct sockaddr *)&alternate_addr, &alternate_addrlen,
      &bandwidth, &lifetime,
      STUN_USAGE_TURN_COMPATIBILITY_DRAFT9);
  assert (val == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS);

  printaddr ("Relay address found : ", (struct sockaddr *)&relay_addr, relay_addrlen);
  printaddr ("Mapped address found : ",(struct sockaddr *) &addr, addrlen);


  req_len = stun_usage_turn_create_refresh (&agent, &refresh_msg, refresh,
      sizeof(refresh),  &req_msg, 0, username, strlen (username),
      password, strlen(password),STUN_USAGE_TURN_COMPATIBILITY_DRAFT9);
  assert (req_len > 0);

  val = send (fd, refresh, req_len, MSG_NOSIGNAL);
  assert (val >= 0);

  val = recv (fd, buf, 1000, 0);
  assert (val >= 0);

  assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL)
      == STUN_VALIDATION_SUCCESS);

  val = close (fd);
  assert (val == 0);
}
Exemplo n.º 3
0
/* 
 * Timer callback that handles scheduling new candidate discovery
 * processes (paced by the Ta timer), and handles running of the 
 * existing discovery processes.
 *
 * This function is designed for the g_timeout_add() interface.
 *
 * @return will return FALSE when no more pending timers.
 */
static gboolean priv_discovery_tick_unlocked (gpointer pointer)
{
  CandidateDiscovery *cand;
  NiceAgent *agent = pointer;
  GSList *i;
  int not_done = 0; /* note: track whether to continue timer */
  size_t buffer_len = 0;

  {
    static int tick_counter = 0;
    if (tick_counter++ % 50 == 0)
      nice_debug ("Agent %p : discovery tick #%d with list %p (1)", agent, tick_counter, agent->discovery_list);
  }

  for (i = agent->discovery_list; i ; i = i->next) {
    cand = i->data;

    if (cand->pending != TRUE) {
      cand->pending = TRUE;

      if (agent->discovery_unsched_items)
	--agent->discovery_unsched_items;

      if (nice_debug_is_enabled ()) {
        gchar tmpbuf[INET6_ADDRSTRLEN];
        nice_address_to_string (&cand->server, tmpbuf);
        nice_debug ("Agent %p : discovery - scheduling cand type %u addr %s.",
            agent, cand->type, tmpbuf);
      }
      if (nice_address_is_valid (&cand->server) &&
          (cand->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
              cand->type == NICE_CANDIDATE_TYPE_RELAYED)) {

        if (cand->component->state == NICE_COMPONENT_STATE_DISCONNECTED ||
            cand->component->state == NICE_COMPONENT_STATE_FAILED)
          agent_signal_component_state_change (agent,
					       cand->stream->id,
					       cand->component->id,
					       NICE_COMPONENT_STATE_GATHERING);

        if (cand->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) {
          buffer_len = stun_usage_bind_create (&cand->stun_agent,
              &cand->stun_message, cand->stun_buffer, sizeof(cand->stun_buffer));
        } else if (cand->type == NICE_CANDIDATE_TYPE_RELAYED) {
          uint8_t *username = (uint8_t *)cand->turn->username;
          gsize username_len = strlen (cand->turn->username);
          uint8_t *password = (uint8_t *)cand->turn->password;
          gsize password_len = strlen (cand->turn->password);
          StunUsageTurnCompatibility turn_compat =
              agent_to_turn_compatibility (agent);

          if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
              turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
            username = g_base64_decode ((gchar *)username, &username_len);
            password = g_base64_decode ((gchar *)password, &password_len);
          }

          buffer_len = stun_usage_turn_create (&cand->stun_agent,
              &cand->stun_message,  cand->stun_buffer, sizeof(cand->stun_buffer),
              cand->stun_resp_msg.buffer == NULL ? NULL : &cand->stun_resp_msg,
              STUN_USAGE_TURN_REQUEST_PORT_NORMAL,
              -1, -1,
              username, username_len,
              password, password_len,
              turn_compat);

          if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
              turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
            g_free (username);
            g_free (password);
          }
        }

	if (buffer_len > 0) {
          if (nice_socket_is_reliable (cand->nicesock)) {
            stun_timer_start_reliable (&cand->timer, agent->stun_reliable_timeout);
          } else {
            stun_timer_start (&cand->timer,
                agent->stun_initial_timeout,
                agent->stun_max_retransmissions);
          }

          /* send the conncheck */
          agent_socket_send (cand->nicesock, &cand->server,
              buffer_len, (gchar *)cand->stun_buffer);

	  /* case: success, start waiting for the result */
	  g_get_current_time (&cand->next_tick);

	} else {
	  /* case: error in starting discovery, start the next discovery */
	  cand->done = TRUE;
	  cand->stun_message.buffer = NULL;
	  cand->stun_message.buffer_len = 0;
	  continue;
	}
      }
      else
	/* allocate relayed candidates */
	g_assert_not_reached ();

      ++not_done; /* note: new discovery scheduled */
    }

    if (cand->done != TRUE) {
      GTimeVal now;

      g_get_current_time (&now);

      if (cand->stun_message.buffer == NULL) {
	nice_debug ("Agent %p : STUN discovery was cancelled, marking discovery done.", agent);
	cand->done = TRUE;
      }
      else if (priv_timer_expired (&cand->next_tick, &now)) {
        switch (stun_timer_refresh (&cand->timer)) {
          case STUN_USAGE_TIMER_RETURN_TIMEOUT:
            {
              /* Time out */
              /* case: error, abort processing */
              StunTransactionId id;

              stun_message_id (&cand->stun_message, id);
              stun_agent_forget_transaction (&cand->stun_agent, id);

              cand->done = TRUE;
              cand->stun_message.buffer = NULL;
              cand->stun_message.buffer_len = 0;
              nice_debug ("Agent %p : bind discovery timed out, aborting discovery item.", agent);
              break;
            }
          case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
            {
              /* case: not ready complete, so schedule next timeout */
              unsigned int timeout = stun_timer_remainder (&cand->timer);

              stun_debug ("STUN transaction retransmitted (timeout %dms).",
                  timeout);

              /* retransmit */
              agent_socket_send (cand->nicesock, &cand->server,
                  stun_message_length (&cand->stun_message),
                  (gchar *)cand->stun_buffer);

              /* note: convert from milli to microseconds for g_time_val_add() */
              cand->next_tick = now;
              g_time_val_add (&cand->next_tick, timeout * 1000);

              ++not_done; /* note: retry later */
              break;
            }
          case STUN_USAGE_TIMER_RETURN_SUCCESS:
            {
              unsigned int timeout = stun_timer_remainder (&cand->timer);

              cand->next_tick = now;
              g_time_val_add (&cand->next_tick, timeout * 1000);

              ++not_done; /* note: retry later */
              break;
            }
          default:
            /* Nothing to do. */
            break;
	}

      } else {
	++not_done; /* note: discovery not expired yet */
      }
    }
  }

  if (not_done == 0) {
    nice_debug ("Agent %p : Candidate gathering FINISHED, stopping discovery timer.", agent);

    discovery_free (agent);

    agent_gathering_done (agent);

    /* note: no pending timers, return FALSE to stop timer */
    return FALSE;
  }

  return TRUE;
}