NicerConnection源码分析

static bool nicer_initialized = false;
static std::mutex nicer_initialization_mutex;

static int nr_ice_crypto_openssl_random_bytes(UCHAR *buf, int len) {
  RAND_bytes(buf, len);
  return 0;
}

static int nr_ice_crypto_openssl_hmac_sha1(UCHAR *key, int key_l, UCHAR *buf, int buf_l, UCHAR digest[20]) {
  unsigned int rl;

  HMAC(EVP_sha1(),
    key, key_l, buf, buf_l, digest, &rl);

  if (rl != 20)
    ERETURN(R_INTERNAL);

  return 0;
}

static int nr_ice_crypto_openssl_md5(UCHAR *buf, int bufl, UCHAR *result) {
  MD5(buf, bufl, result);
  return 0;
}

static nr_ice_crypto_vtbl nr_ice_crypto_openssl_vtbl = {
  nr_ice_crypto_openssl_random_bytes,
  nr_ice_crypto_openssl_hmac_sha1,
  nr_ice_crypto_openssl_md5
};


int nr_crypto_openssl_set() {
  OpenSSL_add_all_algorithms();

  nr_crypto_vtbl = &nr_ice_crypto_openssl_vtbl;

  return 0;
}

void NicerConnection::gather_callback(NR_SOCKET s, int h, void *arg) {
  NicerConnection *conn = reinterpret_cast<NicerConnection*>(arg);
  conn->gatheringDone(h);
}

int NicerConnection::select_pair(void *obj, nr_ice_media_stream *stream,
                                 int component_id, nr_ice_cand_pair **potentials,
                                 int potential_ct) {
  return 0;
}

int NicerConnection::stream_ready(void *obj, nr_ice_media_stream *stream) {
  return 0;
}

int NicerConnection::stream_failed(void *obj, nr_ice_media_stream *stream) {
  NicerConnection *conn = reinterpret_cast<NicerConnection*>(obj);
  conn->updateIceState(IceState::FAILED);
  return 0;
}

int NicerConnection::ice_checking(void *obj, nr_ice_peer_ctx *pctx) {
  return 0;
}

int NicerConnection::ice_connected(void *obj, nr_ice_peer_ctx *pctx) {
  NicerConnection *conn = reinterpret_cast<NicerConnection*>(obj);
  if (conn->checkIceState() == IceState::FAILED) {
    return 0;
  }
  conn->updateIceState(IceState::READY);
  conn->nicer_->IceContextFinalize(conn->ctx_, pctx);

  return 0;
}

int NicerConnection::ice_disconnected(void *obj, nr_ice_peer_ctx *pctx) {
  return 0;
}

int NicerConnection::msg_recvd(void *obj, nr_ice_peer_ctx *pctx,
                               nr_ice_media_stream *stream, int component_id,
                               unsigned char *msg, int len) {
  NicerConnection *conn = reinterpret_cast<NicerConnection*>(obj);
  conn->onData(component_id, reinterpret_cast<char*> (msg), static_cast<unsigned int> (len));
  return 0;
}

void NicerConnection::trickle_callback(void *arg, nr_ice_ctx *ctx, nr_ice_media_stream *stream,
                                       int component_id, nr_ice_candidate *candidate) {
  NicerConnection *conn = reinterpret_cast<NicerConnection*>(arg);
  conn->onCandidate(stream, component_id, candidate);
}

NicerConnection::NicerConnection(std::shared_ptr<IOWorker> io_worker, std::shared_ptr<NicerInterface> interface,
                                 const IceConfig& ice_config)
    : IceConnection(ice_config),
      io_worker_{io_worker},
      nicer_{interface},
      ice_config_{ice_config},
      closed_{false},
      name_{ice_config_.transport_name},
      ctx_{nullptr},
      peer_{nullptr},
      stream_{nullptr},
      offerer_{!ice_config_.username.empty() && !ice_config_.password.empty()} {
}

NicerConnection::~NicerConnection() {
}

void NicerConnection::async(function<void(std::shared_ptr<NicerConnection>)> f) {
  std::weak_ptr<NicerConnection> weak_this = shared_from_this();
  io_worker_->task([weak_this, f] {
    if (auto this_ptr = weak_this.lock()) {
      f(this_ptr);
    }
  });
}

void NicerConnection::start() {
  ufrag_ = getNewUfrag();
  upass_ = getNewPwd();

  async([] (std::shared_ptr<NicerConnection> this_ptr) {
    this_ptr->startSync();
  });
}

void NicerConnection::startSync() {
  UINT4 flags = NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;

  if (ufrag_.empty() || upass_.empty()) {
    start_promise_.set_value();
    return;
  }

  int r = nicer_->IceContextCreateWithCredentials(const_cast<char *>(name_.c_str()),
                                                  flags,
                                                  const_cast<char*>(ufrag_.c_str()),
                                                  const_cast<char*>(upass_.c_str()), &ctx_);
  if (r) {
    ELOG_WARN("%s message: Couldn't create ICE ctx", toLog());
    start_promise_.set_value();
    return;
  }

  r = nicer_->IceContextSetTrickleCallback(ctx_, &NicerConnection::trickle_callback, this);
  if (r) {
    ELOG_WARN("%s message: Couldn't set trickle callback", toLog());
    start_promise_.set_value();
    return;
  }

  // Create the handler objects
  ice_handler_vtbl_ = new nr_ice_handler_vtbl();
  ice_handler_vtbl_->select_pair = &NicerConnection::select_pair;
  ice_handler_vtbl_->stream_ready = &NicerConnection::stream_ready;
  ice_handler_vtbl_->stream_failed = &NicerConnection::stream_failed;
  ice_handler_vtbl_->ice_connected = &NicerConnection::ice_connected;
  ice_handler_vtbl_->msg_recvd = &NicerConnection::msg_recvd;
  ice_handler_vtbl_->ice_checking = &NicerConnection::ice_checking;
  ice_handler_vtbl_->ice_disconnected = &NicerConnection::ice_disconnected;

  ice_handler_ = new nr_ice_handler();
  ice_handler_->vtbl = ice_handler_vtbl_;
  ice_handler_->obj = this;

  // Create the peer ctx. Because we do not support parallel forking, we
  // only have one peer ctx.
  std::string peer_name = name_ + ":default";
  r = nicer_->IcePeerContextCreate(ctx_, ice_handler_, const_cast<char *>(peer_name.c_str()), &peer_);
  if (r) {
    ELOG_WARN("%s message: Couldn't create ICE peer ctx", toLog());
    start_promise_.set_value();
    return;
  }

  std::string stream_name = name_ + ":stream";
  r = nicer_->IceAddMediaStream(ctx_, const_cast<char *>(stream_name.c_str()), ice_config_.ice_components, &stream_);
  if (r) {
    ELOG_WARN("%s message: Couldn't create ICE stream", toLog());
    start_promise_.set_value();
    return;
  }

  if (!ice_config_.network_interface.empty()) {
    std::string interface = ice_config_.network_interface;
    std::copy(interface.begin(),
              (interface.size() >= 32 ? interface.begin() + 32 : interface.end()),
              ctx_->force_net_interface);
  }

  if (ice_config_.min_port != 0 && ice_config_.max_port != 0) {
    ELOG_DEBUG("%s message: setting port range, min_port: %d, max_port: %d",
               toLog(), ice_config_.min_port, ice_config_.max_port);
    nicer_->IceContextSetPortRange(ctx_, ice_config_.min_port, ice_config_.max_port);
  }


  setupTurnServer();
  setupStunServer();

  startGathering();

  if (ice_config_.username.compare("") != 0 && ice_config_.password.compare("") != 0) {
    ELOG_DEBUG("%s message: setting remote credentials in constructor, ufrag:%s, pass:%s",
               toLog(), ice_config_.username.c_str(), ice_config_.password.c_str());
    setRemoteCredentialsSync(ice_config_.username, ice_config_.password);
  } else {
    peer_->controlling = 1;
  }

  start_promise_.set_value();
}

void NicerConnection::setupTurnServer() {
  if (ice_config_.turn_server.empty()) {
    return;
  }
  auto servers = std::unique_ptr<nr_ice_turn_server[]>(new nr_ice_turn_server[1]);
  nr_ice_turn_server *server = &servers[0];
  nr_ice_stun_server *stun_server = &server->turn_server;
  memset(server, 0, sizeof(nr_ice_turn_server));
  stun_server->transport = IPPROTO_UDP;
  stun_server->type = NR_ICE_STUN_SERVER_TYPE_ADDR;
  nr_transport_addr addr;
  nr_str_port_to_transport_addr(ice_config_.turn_server.c_str(), ice_config_.turn_port, IPPROTO_UDP, &addr);
  stun_server->u.addr = addr;

  server->username = r_strdup(const_cast<char*>(ice_config_.turn_username.c_str()));
  int r = r_data_create(&server->password,
                        reinterpret_cast<UCHAR*>(const_cast<char *>(&ice_config_.turn_pass[0])),
                        ice_config_.turn_pass.size());
  if (r) {
    RFREE(server->username);
    return;
  }

  r = nicer_->IceContextSetTurnServers(ctx_, servers.get(), 1);
  if (r) {
    ELOG_WARN("%s message: Could not setup Turn", toLog());
  }

  ELOG_DEBUG("%s message: TURN server configured", toLog());
}

void NicerConnection::setupStunServer() {
  if (ice_config_.stun_server.empty()) {
    return;
  }
  auto servers = std::unique_ptr<nr_ice_stun_server[]>(new nr_ice_stun_server[1]);
  nr_ice_stun_server *server = &servers[0];
  memset(server, 0, sizeof(nr_ice_stun_server));
  server->transport = IPPROTO_UDP;
  server->type = NR_ICE_STUN_SERVER_TYPE_ADDR;
  nr_transport_addr addr;
  nr_str_port_to_transport_addr(ice_config_.stun_server.c_str(), ice_config_.stun_port, IPPROTO_UDP, &addr);
  server->u.addr = addr;


  int r = nicer_->IceContextSetStunServers(ctx_, servers.get(), 1);
  if (r) {
    ELOG_WARN("%s meesage: Could not setup Turn", toLog());
  }

  ELOG_DEBUG("%s message: STUN server configured", toLog());
}

void NicerConnection::startGathering() {
  UINT4 r = nicer_->IceGather(ctx_, &NicerConnection::gather_callback, this);
  if (r && r != R_WOULDBLOCK) {
    ELOG_WARN("%s message: Couldn't start ICE gathering", toLog());
    assert(false);
  }
  ELOG_INFO("%s message: start gathering", toLog());
}

bool NicerConnection::setRemoteCandidates(const std::vector<CandidateInfo> &candidates, bool is_bundle) {
  std::vector<CandidateInfo> cands(candidates);
  auto remote_candidates_promise = std::make_shared<std::promise<void>>();
  nr_ice_peer_ctx *peer = peer_;
  nr_ice_media_stream *stream = stream_;
  std::shared_ptr<NicerInterface> nicer = nicer_;
  async([cands, nicer, peer, stream, this, remote_candidates_promise]
          (std::shared_ptr<NicerConnection> this_ptr) {
    ELOG_DEBUG("%s message: adding remote candidates (%ld)", toLog(), cands.size());
    for (const CandidateInfo &cand : cands) {
      std::string sdp = cand.sdp;
      std::size_t pos = sdp.find(",");
      std::string candidate = sdp.substr(0, pos);
      ELOG_DEBUG("%s message: New remote ICE candidate (%s)", toLog(), candidate.c_str());
      UINT4 r = nicer->IcePeerContextParseTrickleCandidate(peer, stream, const_cast<char *>(candidate.c_str()));
      if (r && r != R_ALREADY) {
        ELOG_WARN("%s message: Couldn't add remote ICE candidate (%s) (%d)", toLog(), candidate.c_str(), r);
      }
    }
    remote_candidates_promise->set_value();
  });
  std::future<void> remote_candidates_future = remote_candidates_promise->get_future();
  std::future_status status = remote_candidates_future.wait_for(std::chrono::seconds(1));
  if (status == std::future_status::timeout) {
    ELOG_WARN("%s message: Could not set remote candidates", toLog());
    return false;
  }
  return true;
}

void NicerConnection::gatheringDone(uint stream_id) {
  ELOG_INFO("%s message: gathering done, stream_id: %u", toLog(), stream_id);
  updateIceState(IceState::CANDIDATES_RECEIVED);
}

void NicerConnection::startChecking() {
  UINT4 r = nicer_->IcePeerContextPairCandidates(peer_);
  if (r) {
    ELOG_WARN("%s message: Error pairing candidates (%d)", toLog(), r);
    return;
  }

  r = nicer_->IcePeerContextStartChecks2(peer_, 1);
  if (r) {
    if (r == R_NOT_FOUND) {
      ELOG_DEBUG("%s message: Could not start ICE checks, assuming trickle", toLog());
    } else {
      ELOG_WARN("%s message: Could not start peer checks", toLog());
    }
  }
  ELOG_DEBUG("Checks started");
}

std::string NicerConnection::getStringFromAddress(const nr_transport_addr &addr) {
  char str[INET_ADDRSTRLEN];
  if (addr.ip_version == NR_IPV4) {
    inet_ntop(AF_INET, &(reinterpret_cast<sockaddr_in*>(addr.addr)->sin_addr), str, INET_ADDRSTRLEN);
  } else {
    inet_ntop(AF_INET, &(reinterpret_cast<sockaddr_in6*>(addr.addr)->sin6_addr), str, INET_ADDRSTRLEN);
  }
  return std::string(str);
}

int NicerConnection::getPortFromAddress(const nr_transport_addr &addr) {
  if (addr.ip_version == NR_IPV4) {
    return ntohs(reinterpret_cast<sockaddr_in*>(addr.addr)->sin_port);
  } else {
    return ntohs(reinterpret_cast<sockaddr_in6*>(addr.addr)->sin6_port);
  }
}

void NicerConnection::onCandidate(nr_ice_media_stream *stream, int component_id, nr_ice_candidate *cand) {
  CandidateInfo cand_info;
  cand_info.componentId = cand->component_id;
  cand_info.foundation = std::string(cand->foundation);
  cand_info.priority = cand->priority;
  if (cand->addr.ip_version != NR_IPV4) {
    return;
  }
  cand_info.hostAddress = getStringFromAddress(cand->addr);
  cand_info.hostPort = getPortFromAddress(cand->addr);
  if (cand_info.hostPort == 0) {
    return;
  }
  cand_info.mediaType = ice_config_.media_type;

  switch (cand->type) {
    case nr_ice_candidate_type::HOST:
      cand_info.hostType = HOST;
      break;
    case SERVER_REFLEXIVE:
      cand_info.hostType = SRFLX;
      cand_info.rAddress = getStringFromAddress(cand->base);
      cand_info.rPort = getPortFromAddress(cand->base);
      break;
    case PEER_REFLEXIVE:
      cand_info.hostType = PRFLX;
      break;
    case RELAYED:
      cand_info.hostType = RELAY;
      cand_info.rAddress = getStringFromAddress(cand->base);
      cand_info.rPort = getPortFromAddress(cand->base);
      break;
    default:
      break;
  }
  cand_info.netProtocol = "udp";
  cand_info.transProtocol = ice_config_.transport_name;
  cand_info.username = ufrag_;
  cand_info.password = upass_;

  if (auto listener = getIceListener().lock()) {
    ELOG_DEBUG("%s message: Candidate (%s, %s, %s)", toLog(), cand_info.hostAddress.c_str(),
                                                     ufrag_.c_str(), upass_.c_str());
    listener->onCandidate(cand_info, this);
  }
}

void NicerConnection::setRemoteCredentials(const std::string& username, const std::string& password) {
  auto promise = std::make_shared<std::promise<void>>();
  async([username, password, promise] (std::shared_ptr<NicerConnection> this_ptr) {
    this_ptr->setRemoteCredentialsSync(username, password);
    promise->set_value();
  });
  auto status = promise->get_future().wait_for(std::chrono::seconds(1));
  if (status == std::future_status::timeout) {
    ELOG_WARN("%s message: Could not set remote credentials", toLog());
  }
}

void NicerConnection::setRemoteCredentialsSync(const std::string& username, const std::string& password) {
  ELOG_DEBUG("%s message: Setting remote credentials", toLog());
  std::vector<char *> attributes;
  std::string ufrag = std::string("ice-ufrag: ") + username;
  std::string pwd = std::string("ice-pwd: ") + password;
  attributes.push_back(const_cast<char *>(ufrag.c_str()));
  attributes.push_back(const_cast<char *>(pwd.c_str()));
  UINT4 r = nicer_->IcePeerContextParseStreamAttributes(peer_,
                                                        stream_,
                                                        attributes.size() ? &attributes[0] : nullptr,
                                                        attributes.size());
  if (r) {
    ELOG_WARN("%s message: Error parsing stream attributes", toLog());
    return;
  }

  startChecking();
}

int NicerConnection::sendData(unsigned int component_id, const void* buf, int len) {
  if (checkIceState() != IceState::READY) {
    return -1;
  }
  packetPtr packet (new DataPacket());
  memcpy(packet->data, buf, len);
  packet->length = len;
  nr_ice_peer_ctx *peer = peer_;
  nr_ice_media_stream *stream = stream_;
  std::shared_ptr<NicerInterface> nicer = nicer_;
  async([nicer, packet, peer, stream, component_id, len] (std::shared_ptr<NicerConnection> this_ptr) {
    UINT4 r = nicer->IceMediaStreamSend(peer,
                                         stream,
                                         component_id,
                                         reinterpret_cast<unsigned char*>(packet->data),
                                         len);
    if (r) {
      ELOG_WARN("%s message: Couldn't send data on ICE", this_ptr->toLog());
    }
  });

  return len;
}

std::string getHostTypeFromNicerCandidate(nr_ice_candidate *candidate) {
  switch (candidate->type) {
    case nr_ice_candidate_type::HOST: return "host";
    case SERVER_REFLEXIVE: return "serverReflexive";
    case PEER_REFLEXIVE: return "peerReflexive";
    case RELAYED: return "relayed";
    default: return "unknown";
  }
}

CandidatePair NicerConnection::getSelectedPair() {
  auto selected_pair_promise = std::make_shared<std::promise<CandidatePair>>();
  async([this, selected_pair_promise] (std::shared_ptr<NicerConnection> this_ptr) {
    nr_ice_candidate *local;
    nr_ice_candidate *remote;
    nicer_->IceMediaStreamGetActive(peer_, stream_, 1, &local, &remote);
    CandidatePair pair;
    if (!local || !remote) {
      selected_pair_promise->set_value(CandidatePair{});
      return;
    }
    pair.clientCandidateIp = getStringFromAddress(remote->addr);
    pair.erizoCandidateIp = getStringFromAddress(local->addr);
    pair.clientCandidatePort = getPortFromAddress(remote->addr);
    pair.erizoCandidatePort = getPortFromAddress(local->addr);
    pair.clientHostType = getHostTypeFromNicerCandidate(remote);
    pair.erizoHostType = getHostTypeFromNicerCandidate(local);
    ELOG_DEBUG("%s message: Client Host Type %s", toLog(), pair.clientHostType.c_str());
    selected_pair_promise->set_value(pair);
  });
  std::future<CandidatePair> selected_pair_future = selected_pair_promise->get_future();
  std::future_status status = selected_pair_future.wait_for(std::chrono::seconds(1));
  CandidatePair pair = selected_pair_future.get();
  if (status == std::future_status::timeout) {
    ELOG_WARN("%s message: Could not get selected pair", toLog());
    return CandidatePair{};
  }
  return pair;
}

void NicerConnection::setReceivedLastCandidate(bool hasReceived) {
}

void NicerConnection::closeSync() {
  if (closed_) {
    return;
  }
  if (auto listener = getIceListener().lock()) {
    listener_.reset();
  }
  if (stream_) {
    nicer_->IceRemoveMediaStream(ctx_, &stream_);
  }
  if (peer_) {
    nicer_->IcePeerContextDestroy(&peer_);
  }
  if (ctx_) {
    nicer_->IceContextDestroy(&ctx_);
  }
  delete ice_handler_vtbl_;
  delete ice_handler_;
  closed_ = true;
}

void NicerConnection::close() {
  if (!closed_) {
    auto shared_this = shared_from_this();
    async([shared_this] (std::shared_ptr<NicerConnection> this_ptr) {
      shared_this->closeSync();
    });
  }
}

void NicerConnection::onData(unsigned int component_id, char* buf, int len) {
  IceState state;
  {
    boost::mutex::scoped_lock lock(close_mutex_);
    state = this->checkIceState();
  }
  if (state == IceState::READY) {
    packetPtr packet (new DataPacket());
    memcpy(packet->data, buf, len);
    packet->comp = component_id;
    packet->length = len;
    packet->received_time_ms = ClockUtils::timePointToMs(clock::now());
    if (auto listener = getIceListener().lock()) {
      listener->onPacketReceived(packet);
    }
  }
}

void NicerConnection::initializeGlobals() {
  std::lock_guard<std::mutex> guard(nicer_initialization_mutex);
  if (!nicer_initialized) {
    nicer_initialized = true;
    NR_reg_init(NR_REG_MODE_LOCAL);

    nr_crypto_openssl_set();

    // Set the priorites for candidate type preferences.
    // These numbers come from RFC 5245 S. 4.1.2.2
    NR_reg_set_uchar(const_cast<char *>(NR_ICE_REG_PREF_TYPE_SRV_RFLX), 100);
    NR_reg_set_uchar(const_cast<char *>(NR_ICE_REG_PREF_TYPE_PEER_RFLX), 110);
    NR_reg_set_uchar(const_cast<char *>(NR_ICE_REG_PREF_TYPE_HOST), 126);
    NR_reg_set_uchar(const_cast<char *>(NR_ICE_REG_PREF_TYPE_RELAYED), 5);
    NR_reg_set_uchar(const_cast<char *>(NR_ICE_REG_PREF_TYPE_RELAYED_TCP), 0);


    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.rl0"), 255);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.wi0"), 254);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.lo0"), 253);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.en1"), 252);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.en0"), 251);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.eth0"), 252);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.eth1"), 251);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.eth2"), 249);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.ppp"), 250);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.ppp0"), 249);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.en2"), 248);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.en3"), 247);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.em0"), 251);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.em1"), 252);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.vmnet0"), 240);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.vmnet1"), 241);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.vmnet3"), 239);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.vmnet4"), 238);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.vmnet5"), 237);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.vmnet6"), 236);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.vmnet7"), 235);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.vmnet8"), 234);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.virbr0"), 233);
    NR_reg_set_uchar(const_cast<char *>("ice.pref.interface.wlan0"), 232);

    NR_reg_set_uint4(const_cast<char *>("stun.client.maximum_transmits"), 7);
    NR_reg_set_uint4(const_cast<char *>(NR_ICE_REG_TRICKLE_GRACE_PERIOD), 5000);

    NR_reg_set_char(const_cast<char *>(NR_ICE_REG_ICE_TCP_DISABLE), true);
    NR_reg_set_char(const_cast<char *>(NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS), 1);
  }
}

std::string NicerConnection::getNewUfrag() {
  char* ufrag;
  int r;

  if ((r=nicer_->IceGetNewIceUFrag(&ufrag))) {
    ELOG_WARN("%s message: Unable to get new ice ufrag", toLog());
    return "";
  }

  std::string ufragStr = ufrag;
  RFREE(ufrag);

  return ufragStr;
}

std::string NicerConnection::getNewPwd() {
  char* pwd;
  int r;

  if ((r=nicer_->IceGetNewIcePwd(&pwd))) {
    ELOG_WARN("%s message: Unable to get new ice pwd", toLog());
    return "";
  }

  std::string pwdStr = pwd;
  RFREE(pwd);

  return pwdStr;
}

std::shared_ptr<IceConnection> NicerConnection::create(std::shared_ptr<IOWorker> io_worker,
                                                       const IceConfig& ice_config) {
  auto nicer = std::make_shared<NicerConnection>(io_worker, std::make_shared<NicerInterfaceImpl>(),
                                                 ice_config);

  NicerConnection::initializeGlobals();

  return nicer;
}

猜你喜欢

转载自blog.csdn.net/tong5956/article/details/108362646