예제 #1
0
int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
{
  nr_turn_stun_ctx *stun = 0;

  if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED ||
      ctx->state == NR_TURN_CLIENT_STATE_FAILED)
    return(0);

  if (ctx->label)
    r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): cancelling", ctx->label);

  /* Cancel the STUN client ctxs */
  stun = STAILQ_FIRST(&ctx->stun_ctxs);
  while (stun) {
    nr_stun_client_cancel(stun->stun);
    stun = STAILQ_NEXT(stun, entry);
  }

  /* Cancel the timers, if not already cancelled */
  NR_async_timer_cancel(ctx->connected_timer_handle);
  NR_async_timer_cancel(ctx->refresh_timer_handle);

  ctx->state = NR_TURN_CLIENT_STATE_CANCELLED;

  return(0);
}
예제 #2
0
int nr_ice_candidate_pair_destroy(nr_ice_cand_pair **pairp)
  {
    nr_ice_cand_pair *pair;

    if(!pairp || !*pairp)
      return(0);

    pair=*pairp;
    *pairp=0;

    RFREE(pair->as_string);
    RFREE(pair->foundation);
    nr_ice_socket_deregister(pair->local->isock,pair->stun_client_handle);
    if (pair->stun_client) {
      RFREE(pair->stun_client->params.ice_binding_request.username);
      RFREE(pair->stun_client->params.ice_binding_request.password.data);
      nr_stun_client_ctx_destroy(&pair->stun_client);
    }

    NR_async_timer_cancel(pair->stun_cb_timer);
    NR_async_timer_cancel(pair->restart_role_change_cb_timer);
    NR_async_timer_cancel(pair->restart_nominated_cb_timer);

    RFREE(pair);
    return(0);
  }
예제 #3
0
int nr_stun_client_force_retransmit(nr_stun_client_ctx *ctx)
  {
    int r,_status;

    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
        ABORT(R_NOT_PERMITTED);

    if (ctx->request_ct > ctx->maximum_transmits) {
        r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Too many retransmit attempts",ctx->label);
        ABORT(R_FAILED);
    }

    /* if there is a scheduled retransimt, get rid of the scheduled retransmit
     * and retransmit immediately */
    if (ctx->timer_handle) {
        NR_async_timer_cancel(ctx->timer_handle);
        ctx->timer_handle=0;

        if (r=nr_stun_client_send_request(ctx))
            ABORT(r);
    }

    _status=0;
  abort:

    return(_status);
  }
예제 #4
0
int
nr_stun_client_reset(nr_stun_client_ctx *ctx)
{
    /* Cancel the timer firing */
    if (ctx->timer_handle){
        NR_async_timer_cancel(ctx->timer_handle);
        ctx->timer_handle=0;
    }

    nr_stun_message_destroy(&ctx->request);
    ctx->request   = 0;

    nr_stun_message_destroy(&ctx->response);
    ctx->response  = 0;

    memset(&ctx->results, 0, sizeof(ctx->results));

    ctx->mode          = 0;
    ctx->finished_cb   = 0;
    ctx->cb_arg        = 0;
    ctx->request_ct    = 0;
    ctx->timeout_ms    = 0;

    ctx->state = NR_STUN_CLIENT_STATE_INITTED;

    return 0;
}
예제 #5
0
static void nr_turn_client_connected_cb(NR_SOCKET s, int how, void *cb_arg)
{
  int r, _status;
  nr_turn_client_ctx *ctx = (nr_turn_client_ctx *)cb_arg;

  /* Cancel the connection failure timer */
  NR_async_timer_cancel(ctx->connected_timer_handle);
  ctx->connected_timer_handle=0;

  /* Assume we connected successfully */
  if (ctx->state == NR_TURN_CLIENT_STATE_ALLOCATION_WAIT) {
    if ((r=nr_turn_stun_ctx_start(STAILQ_FIRST(&ctx->stun_ctxs))))
      ABORT(r);
    ctx->state = NR_TURN_CLIENT_STATE_ALLOCATING;
  }
  else {
    ctx->state = NR_TURN_CLIENT_STATE_CONNECTED;
  }

  _status = 0;
abort:
  if (_status) {
    nr_turn_client_failed(ctx);
  }
}
예제 #6
0
int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
{
  nr_turn_stun_ctx *stun = 0;

  if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED ||
      ctx->state == NR_TURN_CLIENT_STATE_FAILED)
    return 0;

  if (ctx->label)
    r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): cancelling", ctx->label);

  /* If we are waiting for connect, we need to stop
     waiting for writability */
  if (ctx->state == NR_TURN_CLIENT_STATE_INITTED ||
      ctx->state == NR_TURN_CLIENT_STATE_ALLOCATION_WAIT) {
    NR_SOCKET fd;
    int r;

    r = nr_socket_getfd(ctx->sock, &fd);
    if (r) {
      /* We should be able to get the fd, but if we get an
         error, we shouldn't cancel. */
      r_log(NR_LOG_TURN, LOG_ERR, "TURN: Couldn't get internal fd");
    }
    else {
      NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE);
    }
  }

  /* Cancel the STUN client ctxs */
  stun = STAILQ_FIRST(&ctx->stun_ctxs);
  while (stun) {
    nr_stun_client_cancel(stun->stun);
    stun = STAILQ_NEXT(stun, entry);
  }

  /* Cancel the timers, if not already cancelled */
  NR_async_timer_cancel(ctx->connected_timer_handle);
  NR_async_timer_cancel(ctx->refresh_timer_handle);

  ctx->state = NR_TURN_CLIENT_STATE_CANCELLED;

  return(0);
}
예제 #7
0
void TestNrSocket::close() {
  if (timer_handle_) {
    NR_async_timer_cancel(timer_handle_);
    timer_handle_ = 0;
  }
  internal_socket_->close();
  for (RefPtr<PortMapping>& port_mapping : port_mappings_) {
    port_mapping->external_socket_->close();
  }
}
int NrIceResolverFake::cancel(void *obj, void *handle) {
  MOZ_ASSERT(obj);
  MOZ_ASSERT(static_cast<NrIceResolverFake *>(obj)->allocated_resolvers_ > 0);

  PendingResolution *pending = static_cast<PendingResolution *>(handle);

  NR_async_timer_cancel(pending->timer_handle_);
  delete pending;

  return(0);
}
예제 #9
0
static void nr_stun_client_timer_expired_cb(int a, int b, void *cb_arg)
{
    int _status;
    nr_stun_client_ctx *ctx=cb_arg;
    struct timeval now;
    INT8 ms_waited;

    /* Prevent this timer from being cancelled later */
    ctx->timer_handle=0;

    /* Shouldn't happen */
    if(ctx->state==NR_STUN_CLIENT_STATE_CANCELLED)
        ABORT(R_REJECTED);

    gettimeofday(&now, 0);
    if (r_timeval_diff_ms(&now, &ctx->timer_set, &ms_waited)) {
        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired",ctx->label);
    }
    else {
        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired (after %llu ms)",ctx->label, ms_waited);
    }

    if (ctx->request_ct >= ctx->maximum_transmits) {
        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timed out",ctx->label);
        ctx->state=NR_STUN_CLIENT_STATE_TIMED_OUT;
        ABORT(R_FAILED);
    }

    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
        ABORT(R_NOT_PERMITTED);

    /* as a side effect will reset the timer */
    nr_stun_client_send_request(ctx);

    _status = 0;
abort:
    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
        /* Cancel the timer firing */
        if (ctx->timer_handle) {
            NR_async_timer_cancel(ctx->timer_handle);
            ctx->timer_handle=0;
        }

        if (ctx->finished_cb) {
            NR_async_cb finished_cb = ctx->finished_cb;
            ctx->finished_cb = 0;  /* prevent 2nd call */
            /* finished_cb call must be absolutely last thing in function
             * because as a side effect this ctx may be operated on in the
             * callback */
            finished_cb(0,0,ctx->cb_arg);
        }
    }
    return;
}
예제 #10
0
int nr_stun_client_cancel(nr_stun_client_ctx *ctx)
  {
    /* Cancel the timer firing */
    if (ctx->timer_handle){
      NR_async_timer_cancel(ctx->timer_handle);
      ctx->timer_handle=0;
    }

    /* Mark cancelled so we ignore any returned messsages */
    ctx->state=NR_STUN_CLIENT_STATE_CANCELLED;
    return(0);
}
예제 #11
0
static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg)
  {
    int _status;
    nr_stun_client_ctx *ctx=cb_arg;
    struct timeval now;
    INT8 ms_waited;

    /* Prevent this timer from being cancelled later */
    ctx->timer_handle=0;

    /* Shouldn't happen */
    if(ctx->state==NR_STUN_CLIENT_STATE_CANCELLED)
      ABORT(R_REJECTED);

    gettimeofday(&now, 0);
    if (r_timeval_diff_ms(&now, &ctx->timer_set, &ms_waited)) {
        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired",ctx->label);
    }
    else {
        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired (after %llu ms)",ctx->label, ms_waited);
    }

    if (ctx->request_ct >= ctx->maximum_transmits) {
        r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Timed out",ctx->label);
        ctx->state=NR_STUN_CLIENT_STATE_TIMED_OUT;
        ABORT(R_FAILED);
    }

    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
        ABORT(R_NOT_PERMITTED);

    /* as a side effect will reset the timer */
    nr_stun_client_send_request(ctx);

    _status = 0;
  abort:
    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
        /* Cancel the timer firing */
        if (ctx->timer_handle){
            NR_async_timer_cancel(ctx->timer_handle);
            ctx->timer_handle=0;
        }

        nr_stun_client_fire_finished_cb(ctx);
    }
    return;
  }
예제 #12
0
int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr)
  {
    int r,_status;
    char string[256];
    char *username = 0;
    Data *password = 0;
    nr_stun_message_attribute *attr;
    nr_transport_addr *mapped_addr = 0;
    int fail_on_error = 0;
    UCHAR hmac_key_d[16];
    Data hmac_key;
    int compute_lt_key=0;
    /* TODO([email protected]): Bug 1023619, refactor this. */
    int response_matched=0;

    ATTACH_DATA(hmac_key, hmac_key_d);

    if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
        (ctx->state != NR_STUN_CLIENT_STATE_WAITING))
      ABORT(R_REJECTED);

    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Inspecting STUN response (my_addr=%s, peer_addr=%s)",ctx->label,ctx->my_addr.as_string,peer_addr->as_string);

    snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Received ", ctx->label);
    r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)msg, len);

    /* determine password */
    switch (ctx->mode) {
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
      compute_lt_key = 1;
      /* Fall through */
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
        password = ctx->params.stun_binding_request.password;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
        /* do nothing */
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
        /* do nothing */
        break;

#ifdef USE_ICE
    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
        password = &ctx->params.ice_binding_request.password;
        break;
    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
        password = &ctx->params.ice_binding_request.password;
        break;
#endif /* USE_ICE */

#ifdef USE_TURN
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
      fail_on_error = 1;
      compute_lt_key = 1;
        username = ctx->auth_params.username;
        password = &ctx->auth_params.password;
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
      fail_on_error = 1;
      compute_lt_key = 1;
        username = ctx->auth_params.username;
        password = &ctx->auth_params.password;
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
      fail_on_error = 1;
      compute_lt_key = 1;
        username = ctx->auth_params.username;
        password = &ctx->auth_params.password;
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_SEND_INDICATION:
        /* do nothing -- we just got our DATA-INDICATION */
        break;
#endif /* USE_TURN */

    default:
        assert(0);
        ABORT(R_FAILED);
        break;
    }

    if (compute_lt_key) {
      if (!ctx->realm || !username) {
        r_log(NR_LOG_STUN, LOG_DEBUG, "Long-term auth required but no realm/username specified. Randomizing key");
        /* Fill the key with random bytes to guarantee non-match */
        if (r=nr_crypto_random_bytes(hmac_key_d, sizeof(hmac_key_d)))
          ABORT(r);
      }
      else {
        if (r=nr_stun_compute_lt_message_integrity_password(username, ctx->realm,
                                                            password, &hmac_key))
          ABORT(r);
      }
      password = &hmac_key;
    }

    if (ctx->response) {
      nr_stun_message_destroy(&ctx->response);
    }

    /* TODO([email protected]): Bug 1023619, refactor this. */
    if ((r=nr_stun_message_create2(&ctx->response, msg, len)))
        ABORT(r);

    if ((r=nr_stun_decode_message(ctx->response, nr_stun_client_get_password, password))) {
        r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): error decoding response",ctx->label);
        ABORT(r);
    }

    /* This will return an error if request and response don't match,
       which is how we reject responses that match other contexts. */
    if ((r=nr_stun_receive_message(ctx->request, ctx->response))) {
        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Response is not for us",ctx->label);
        ABORT(r);
    }

    r_log(NR_LOG_STUN,LOG_INFO,
          "STUN-CLIENT(%s): Received response; processing",ctx->label);
    response_matched=1;

/* TODO: !nn! currently using password!=0 to mean that auth is required,
 * TODO: !nn! but we should probably pass that in explicitly via the
 * TODO: !nn! usage (ctx->mode?) */
    if (password) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_NONCE, 0)) {
            if ((r=nr_stun_receive_response_long_term_auth(ctx->response, ctx)))
                ABORT(r);
        }
        else {
            if ((r=nr_stun_receive_response_short_term_auth(ctx->response)))
                ABORT(r);
        }
    }

    if (NR_STUN_GET_TYPE_CLASS(ctx->response->header.type) == NR_CLASS_RESPONSE) {
        if ((r=nr_stun_process_success_response(ctx->response)))
            ABORT(r);
    }
    else {
      if (fail_on_error) {
        ctx->state = NR_STUN_CLIENT_STATE_FAILED;
      }
        /* Note: most times we call process_error_response, we get r != 0.

           However, if the error is to be discarded, we get r == 0, smash
           the error code, and just keep going.
        */
        if ((r=nr_stun_process_error_response(ctx->response, &ctx->error_code))) {
            ABORT(r);
        }
        else {
          ctx->error_code = 0xffff;
            /* drop the error on the floor */
            ABORT(R_FAILED);
        }
    }

    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Successfully parsed mode=%d",ctx->label,ctx->mode);

/* TODO: !nn! this should be moved to individual message receive/processing sections */
    switch (ctx->mode) {
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
            if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
              /* Compensate for a bug in Google's STUN servers where they always respond with MAPPED-ADDRESS */
              r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS but MAPPED-ADDRESS. Falling back (though server is wrong).", ctx->label);
            }
            else {
              ABORT(R_BAD_DATA);
            }
        }

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0) && ! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response_stund_0_96.mapped_addr;
        break;

#ifdef USE_ICE
    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;
    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;
#endif /* USE_ICE */

#ifdef USE_TURN
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_RELAY_ADDRESS, &attr))
          ABORT(R_BAD_DATA);

        if ((r=nr_stun_transport_addr_check(&attr->u.relay_address.unmasked,
                                            ctx->mapped_addr_check_mask)))
          ABORT(r);

        if ((r=nr_transport_addr_copy(
                &ctx->results.allocate_response.relay_addr,
                &attr->u.relay_address.unmasked)))
          ABORT(r);

        if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr))
          ABORT(R_BAD_DATA);
        ctx->results.allocate_response.lifetime_secs=attr->u.lifetime_secs;

        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received relay address: %s", ctx->label, ctx->results.allocate_response.relay_addr.as_string);

        mapped_addr = &ctx->results.allocate_response.mapped_addr;

        break;
    case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);
        if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr))
          ABORT(R_BAD_DATA);
        ctx->results.refresh_response.lifetime_secs=attr->u.lifetime_secs;
        break;
    case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);
        break;
#endif /* USE_TURN */

    default:
        assert(0);
        ABORT(R_FAILED);
        break;
    }

    /* make sure we have the most up-to-date address from this peer */
    if (nr_transport_addr_cmp(&ctx->peer_addr, peer_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
        r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Peer moved from %s to %s", ctx->label, ctx->peer_addr.as_string, peer_addr->as_string);
        nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
    }

    if (mapped_addr) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, &attr)) {
            if ((r=nr_stun_transport_addr_check(&attr->u.xor_mapped_address.unmasked,
                                                ctx->mapped_addr_check_mask)))
                ABORT(r);

            if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.xor_mapped_address.unmasked)))
                ABORT(r);
        }
        else if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, &attr)) {
            if ((r=nr_stun_transport_addr_check(&attr->u.mapped_address,
                                                ctx->mapped_addr_check_mask)))
                ABORT(r);

            if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.mapped_address)))
                ABORT(r);
        }
        else
            ABORT(R_BAD_DATA);

        // STUN doesn't distinguish protocol in mapped address, therefore
        // assign used protocol from peer_addr
        if (mapped_addr->protocol!=peer_addr->protocol){
          mapped_addr->protocol=peer_addr->protocol;
          nr_transport_addr_fmt_addr_string(mapped_addr);
        }

        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received mapped address: %s", ctx->label, mapped_addr->as_string);
    }

    ctx->state=NR_STUN_CLIENT_STATE_DONE;

    _status=0;
  abort:
    if(_status && response_matched){
      r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): Error processing response: %s, stun error code %d.", ctx->label, nr_strerror(_status), (int)ctx->error_code);
    }

    if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
        (ctx->state != NR_STUN_CLIENT_STATE_WAITING)) {
        /* Cancel the timer firing */
        if (ctx->timer_handle) {
            NR_async_timer_cancel(ctx->timer_handle);
            ctx->timer_handle = 0;
        }

        nr_stun_client_fire_finished_cb(ctx);
    }

    return(_status);
  }
예제 #13
0
int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr)
{
    int r,_status;
    char string[256];
    Data *password = 0;
    nr_stun_message_attribute *attr;
    nr_transport_addr *mapped_addr = 0;

    if(ctx->state==NR_STUN_CLIENT_STATE_CANCELLED)
        ABORT(R_REJECTED);

    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
        ABORT(R_REJECTED);

    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received(my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,peer_addr->as_string);

    snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Received ", ctx->label);
    r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)msg, len);

    /* determine password */
    switch (ctx->mode) {
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
        password = ctx->params.stun_binding_request.password;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
        /* do nothing */
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
        /* do nothing */
        break;

#ifdef USE_ICE
    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
        password = &ctx->params.ice_binding_request.password;
        break;
    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
        password = &ctx->params.ice_binding_request.password;
        break;
#endif /* USE_ICE */

#ifdef USE_TURN
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1:
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2:
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST:
        /* do nothing */
        break;
    case NR_TURN_CLIENT_MODE_SEND_INDICATION:
        /* do nothing -- we just got our DATA-INDICATION */
        break;
#endif /* USE_TURN */

    default:
        assert(0);
        ABORT(R_FAILED);
        break;
    }

#ifdef USE_TURN
    if (ctx->mode == NR_TURN_CLIENT_MODE_SEND_INDICATION) {
        /* SEND-INDICATION gets a DATA-INDICATION back, which will always
         * be a different transaction, so don't perform the check in that
         * case */
    }
#endif /* USE_TURN */

    if ((r=nr_stun_message_create2(&ctx->response, msg, len)))
        ABORT(r);

    if ((r=nr_stun_decode_message(ctx->response, nr_stun_client_get_password, password)))
        ABORT(r);

    if ((r=nr_stun_receive_message(ctx->request, ctx->response)))
        ABORT(r);

    /* TODO: !nn! currently using password!=0 to mean that auth is required,
     * TODO: !nn! but we should probably pass that in explicitly via the
     * TODO: !nn! usage (ctx->mode?) */
    if (password) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_NONCE, 0)) {
            if ((r=nr_stun_receive_response_long_term_auth(ctx->response, ctx)))
                ABORT(r);
        }
        else {
            if ((r=nr_stun_receive_response_short_term_auth(ctx->response)))
                ABORT(r);
        }
    }

    if (NR_STUN_GET_TYPE_CLASS(ctx->response->header.type) == NR_CLASS_RESPONSE) {
        if ((r=nr_stun_process_success_response(ctx->response)))
            ABORT(r);
    }
    else {
        if ((r=nr_stun_process_error_response(ctx->response))) {
            ABORT(r);
        }
        else {
            /* drop the error on the floor */
            ABORT(R_FAILED);
        }
    }

    /* TODO: !nn! this should be moved to individual message receive/processing sections */
    switch (ctx->mode) {
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;

    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0) && ! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response_stund_0_96.mapped_addr;
        break;

#ifdef USE_ICE
    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;
    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
        break;
#endif /* USE_ICE */

#ifdef USE_TURN
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_REALM, &attr))
            ABORT(R_BAD_DATA);

        ctx->results.allocate_response1.realm = attr->u.realm;

        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_NONCE, &attr))
            ABORT(R_BAD_DATA);

        ctx->results.allocate_response1.nonce = attr->u.nonce;
        break;
    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_USERNAME, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);

        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_RELAY_ADDRESS, &attr)) {
            if ((r=nr_transport_addr_copy(
                        &ctx->results.allocate_response2.relay_addr,
                        &attr->u.relay_address)))
                ABORT(r);
        }
        else {
            if ((r=nr_transport_addr_copy(&ctx->results.allocate_response2.relay_addr, peer_addr)))
                ABORT(r);
        }

        mapped_addr = &ctx->results.allocate_response2.mapped_addr;

        break;
    case NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
            ABORT(R_BAD_DATA);
        break;
    case NR_TURN_CLIENT_MODE_SEND_INDICATION:
        if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_REMOTE_ADDRESS, 0))
            ABORT(R_BAD_DATA);
        break;
#endif /* USE_TURN */

    default:
        assert(0);
        ABORT(R_FAILED);
        break;
    }

    /* make sure we have the most up-to-date address from this peer */
    if (nr_transport_addr_cmp(&ctx->peer_addr, peer_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
        r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Peer moved from %s to %s", ctx->label, ctx->peer_addr.as_string, peer_addr->as_string);
        nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
    }

    if (mapped_addr) {
        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, &attr)) {
            if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.xor_mapped_address.unmasked)))
                ABORT(r);
        }
        else if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, &attr)) {
            if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.mapped_address)))
                ABORT(r);
        }
        else
            ABORT(R_BAD_DATA);

        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received mapped address: %s", ctx->label, mapped_addr->as_string);
    }

    ctx->state=NR_STUN_CLIENT_STATE_DONE;

    _status=0;
abort:
    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
        /* Cancel the timer firing */
        if (ctx->timer_handle) {
            NR_async_timer_cancel(ctx->timer_handle);
            ctx->timer_handle = 0;
        }

        /* Fire the callback */
        if (ctx->finished_cb) {
            NR_async_cb finished_cb = ctx->finished_cb;
            ctx->finished_cb = 0;  /* prevent 2nd call */
            /* finished_cb call must be absolutely last thing in function
             * because as a side effect this ctx may be operated on in the
             * callback */
            finished_cb(0,0,ctx->cb_arg);
        }
    }

    return(_status);
}