1 #include <sstream>
2 
3 #include "logging.h"
4 
5 // nICEr includes
6 extern "C" {
7 #include "nr_api.h"
8 #include "ice_ctx.h"
9 }
10 
11 // Local includes
12 #include "nricectxhandler.h"
13 #include "nricemediastream.h"
14 #include "nriceresolver.h"
15 
16 namespace mozilla {
17 
18 MOZ_MTLOG_MODULE("mtransport")
19 
NrIceCtxHandler(const std::string & name,bool offerer,NrIceCtx::Policy policy)20 NrIceCtxHandler::NrIceCtxHandler(const std::string& name,
21                                  bool offerer,
22                                  NrIceCtx::Policy policy)
23   : current_ctx(new NrIceCtx(name, offerer, policy)),
24     old_ctx(nullptr),
25     restart_count(0)
26 {
27 }
28 
29 RefPtr<NrIceCtxHandler>
Create(const std::string & name,bool offerer,bool allow_loopback,bool tcp_enabled,bool allow_link_local,NrIceCtx::Policy policy)30 NrIceCtxHandler::Create(const std::string& name,
31                         bool offerer,
32                         bool allow_loopback,
33                         bool tcp_enabled,
34                         bool allow_link_local,
35                         NrIceCtx::Policy policy)
36 {
37   // InitializeGlobals only executes once
38   NrIceCtx::InitializeGlobals(allow_loopback, tcp_enabled, allow_link_local);
39 
40   RefPtr<NrIceCtxHandler> ctx = new NrIceCtxHandler(name, offerer, policy);
41 
42   if (ctx == nullptr ||
43       ctx->current_ctx == nullptr ||
44       !ctx->current_ctx->Initialize()) {
45     return nullptr;
46   }
47 
48   return ctx;
49 }
50 
51 
52 RefPtr<NrIceMediaStream>
CreateStream(const std::string & name,int components)53 NrIceCtxHandler::CreateStream(const std::string& name, int components)
54 {
55   // To make tracking NrIceMediaStreams easier during ICE restart
56   // prepend an int to the name that increments with each ICE restart
57   std::ostringstream os;
58   os << restart_count << "-" << name;
59   return NrIceMediaStream::Create(this->current_ctx, os.str(), components);
60 }
61 
62 
63 RefPtr<NrIceCtx>
CreateCtx() const64 NrIceCtxHandler::CreateCtx() const
65 {
66   return CreateCtx(NrIceCtx::GetNewUfrag(), NrIceCtx::GetNewPwd());
67 }
68 
69 
70 RefPtr<NrIceCtx>
CreateCtx(const std::string & ufrag,const std::string & pwd) const71 NrIceCtxHandler::CreateCtx(const std::string& ufrag,
72                            const std::string& pwd) const
73 {
74   RefPtr<NrIceCtx> new_ctx = new NrIceCtx(this->current_ctx->name(),
75                                           true, // offerer (hardcoded per bwc)
76                                           this->current_ctx->policy());
77   if (new_ctx == nullptr) {
78     return nullptr;
79   }
80 
81   if (!new_ctx->Initialize(ufrag, pwd)) {
82     return nullptr;
83   }
84 
85   // copy the stun, and turn servers from the current context
86   int r = nr_ice_ctx_set_stun_servers(new_ctx->ctx_,
87                                       this->current_ctx->ctx_->stun_servers,
88                                       this->current_ctx->ctx_->stun_server_ct);
89   if (r) {
90     MOZ_MTLOG(ML_ERROR, "Error while setting STUN servers in CreateCtx"
91                         << " (likely ice restart related)");
92     return nullptr;
93   }
94 
95   r = nr_ice_ctx_copy_turn_servers(new_ctx->ctx_,
96                                    this->current_ctx->ctx_->turn_servers,
97                                    this->current_ctx->ctx_->turn_server_ct);
98   if (r) {
99     MOZ_MTLOG(ML_ERROR, "Error while copying TURN servers in CreateCtx"
100                         << " (likely ice restart related)");
101     return nullptr;
102   }
103 
104   // grab the NrIceResolver stashed in the nr_resolver and allocate another
105   // for the new ctx.  Note: there may not be an nr_resolver.
106   if (this->current_ctx->ctx_->resolver) {
107     NrIceResolver* resolver =
108       static_cast<NrIceResolver*>(this->current_ctx->ctx_->resolver->obj);
109     if (!resolver ||
110         NS_FAILED(new_ctx->SetResolver(resolver->AllocateResolver()))) {
111       MOZ_MTLOG(ML_ERROR, "Error while setting dns resolver in CreateCtx"
112                           << " (likely ice restart related)");
113       return nullptr;
114     }
115   }
116 
117   return new_ctx;
118 }
119 
120 
121 bool
BeginIceRestart(RefPtr<NrIceCtx> new_ctx)122 NrIceCtxHandler::BeginIceRestart(RefPtr<NrIceCtx> new_ctx)
123 {
124   MOZ_ASSERT(!old_ctx, "existing ice restart in progress");
125   if (old_ctx) {
126     MOZ_MTLOG(ML_ERROR, "Existing ice restart in progress");
127     return false; // ice restart already in progress
128   }
129 
130   if (new_ctx == nullptr) {
131     return false;
132   }
133 
134   ++restart_count;
135   old_ctx = current_ctx;
136   current_ctx = new_ctx;
137   return true;
138 }
139 
140 
141 void
FinalizeIceRestart()142 NrIceCtxHandler::FinalizeIceRestart()
143 {
144   // no harm calling this even if we're not in the middle of restarting
145   old_ctx = nullptr;
146 }
147 
148 
149 void
RollbackIceRestart()150 NrIceCtxHandler::RollbackIceRestart()
151 {
152   if (old_ctx == nullptr) {
153     return;
154   }
155   current_ctx = old_ctx;
156   old_ctx = nullptr;
157 }
158 
159 
160 } // close namespace
161