|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 |
|
8 // Original authors: jib@mozilla.com, ekr@rtfm.com |
|
9 |
|
10 // Some of this code is cut-and-pasted from nICEr. Copyright is: |
|
11 |
|
12 /* |
|
13 Copyright (c) 2007, Adobe Systems, Incorporated |
|
14 All rights reserved. |
|
15 |
|
16 Redistribution and use in source and binary forms, with or without |
|
17 modification, are permitted provided that the following conditions are |
|
18 met: |
|
19 |
|
20 * Redistributions of source code must retain the above copyright |
|
21 notice, this list of conditions and the following disclaimer. |
|
22 |
|
23 * Redistributions in binary form must reproduce the above copyright |
|
24 notice, this list of conditions and the following disclaimer in the |
|
25 documentation and/or other materials provided with the distribution. |
|
26 |
|
27 * Neither the name of Adobe Systems, Network Resonance nor the names of its |
|
28 contributors may be used to endorse or promote products derived from |
|
29 this software without specific prior written permission. |
|
30 |
|
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
32 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
33 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
34 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
35 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
36 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
37 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
38 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
39 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
40 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
41 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
42 */ |
|
43 |
|
44 #include "logging.h" |
|
45 #include "nspr.h" |
|
46 #include "prnetdb.h" |
|
47 |
|
48 #include "mozilla/Assertions.h" |
|
49 |
|
50 extern "C" { |
|
51 #include "nr_api.h" |
|
52 #include "async_timer.h" |
|
53 #include "nr_resolver.h" |
|
54 #include "transport_addr.h" |
|
55 } |
|
56 |
|
57 #include "mozilla/net/DNS.h" // TODO(jib@mozilla.com) down here because bug 848578 |
|
58 #include "nsThreadUtils.h" |
|
59 #include "nsServiceManagerUtils.h" |
|
60 #include "nsIDNSService.h" |
|
61 #include "nsIDNSListener.h" |
|
62 #include "nsIDNSRecord.h" |
|
63 #include "nsNetCID.h" |
|
64 #include "nsCOMPtr.h" |
|
65 #include "nriceresolver.h" |
|
66 #include "nr_socket_prsock.h" |
|
67 #include "mtransport/runnable_utils.h" |
|
68 |
|
69 namespace mozilla { |
|
70 |
|
71 MOZ_MTLOG_MODULE("mtransport") |
|
72 |
|
73 NrIceResolver::NrIceResolver() : |
|
74 vtbl_(new nr_resolver_vtbl()) |
|
75 #ifdef DEBUG |
|
76 , allocated_resolvers_(0) |
|
77 #endif |
|
78 { |
|
79 vtbl_->destroy = &NrIceResolver::destroy; |
|
80 vtbl_->resolve = &NrIceResolver::resolve; |
|
81 vtbl_->cancel = &NrIceResolver::cancel; |
|
82 } |
|
83 |
|
84 NrIceResolver::~NrIceResolver() { |
|
85 MOZ_ASSERT(!allocated_resolvers_); |
|
86 delete vtbl_; |
|
87 } |
|
88 |
|
89 nsresult NrIceResolver::Init() { |
|
90 nsresult rv; |
|
91 |
|
92 sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
|
93 MOZ_ASSERT(NS_SUCCEEDED(rv)); |
|
94 dns_ = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); |
|
95 if (NS_FAILED(rv)) { |
|
96 MOZ_MTLOG(ML_ERROR, "Could not acquire DNS service"); |
|
97 } |
|
98 return rv; |
|
99 } |
|
100 |
|
101 nr_resolver *NrIceResolver::AllocateResolver() { |
|
102 nr_resolver *resolver; |
|
103 |
|
104 int r = nr_resolver_create_int((void *)this, vtbl_, &resolver); |
|
105 MOZ_ASSERT(!r); |
|
106 if(r) { |
|
107 MOZ_MTLOG(ML_ERROR, "nr_resolver_create_int failed"); |
|
108 return nullptr; |
|
109 } |
|
110 // We must be available to allocators until they all call DestroyResolver, |
|
111 // because allocators may (and do) outlive the originator of NrIceResolver. |
|
112 AddRef(); |
|
113 #ifdef DEBUG |
|
114 ++allocated_resolvers_; |
|
115 #endif |
|
116 return resolver; |
|
117 } |
|
118 |
|
119 void NrIceResolver::DestroyResolver() { |
|
120 #ifdef DEBUG |
|
121 --allocated_resolvers_; |
|
122 #endif |
|
123 // Undoes Addref in AllocateResolver so the NrIceResolver can be freed. |
|
124 Release(); |
|
125 } |
|
126 |
|
127 int NrIceResolver::destroy(void **objp) { |
|
128 if (!objp || !*objp) |
|
129 return 0; |
|
130 NrIceResolver *resolver = static_cast<NrIceResolver *>(*objp); |
|
131 *objp = 0; |
|
132 resolver->DestroyResolver(); |
|
133 return 0; |
|
134 } |
|
135 |
|
136 int NrIceResolver::resolve(void *obj, |
|
137 nr_resolver_resource *resource, |
|
138 int (*cb)(void *cb_arg, nr_transport_addr *addr), |
|
139 void *cb_arg, |
|
140 void **handle) { |
|
141 MOZ_ASSERT(obj); |
|
142 return static_cast<NrIceResolver *>(obj)->resolve(resource, cb, cb_arg, handle); |
|
143 } |
|
144 |
|
145 int NrIceResolver::resolve(nr_resolver_resource *resource, |
|
146 int (*cb)(void *cb_arg, nr_transport_addr *addr), |
|
147 void *cb_arg, |
|
148 void **handle) { |
|
149 int _status; |
|
150 MOZ_ASSERT(allocated_resolvers_ > 0); |
|
151 ASSERT_ON_THREAD(sts_thread_); |
|
152 nsRefPtr<PendingResolution> pr; |
|
153 |
|
154 if (resource->transport_protocol != IPPROTO_UDP && |
|
155 resource->transport_protocol != IPPROTO_TCP) { |
|
156 MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are is supported."); |
|
157 ABORT(R_NOT_FOUND); |
|
158 } |
|
159 pr = new PendingResolution(sts_thread_, |
|
160 resource->port? resource->port : 3478, |
|
161 resource->transport_protocol ? |
|
162 resource->transport_protocol : |
|
163 IPPROTO_UDP, |
|
164 cb, cb_arg); |
|
165 if (NS_FAILED(dns_->AsyncResolve(nsAutoCString(resource->domain_name), |
|
166 nsIDNSService::RESOLVE_DISABLE_IPV6, pr, |
|
167 sts_thread_, getter_AddRefs(pr->request_)))) { |
|
168 MOZ_MTLOG(ML_ERROR, "AsyncResolve failed."); |
|
169 ABORT(R_NOT_FOUND); |
|
170 } |
|
171 // Because the C API offers no "finished" method to release the handle we |
|
172 // return, we cannot return the request we got from AsyncResolve directly. |
|
173 // |
|
174 // Instead, we return an addref'ed reference to PendingResolution itself, |
|
175 // which in turn holds the request and coordinates between cancel and |
|
176 // OnLookupComplete to release it only once. |
|
177 pr.forget(handle); |
|
178 |
|
179 _status=0; |
|
180 abort: |
|
181 return _status; |
|
182 } |
|
183 |
|
184 nsresult NrIceResolver::PendingResolution::OnLookupComplete( |
|
185 nsICancelable *request, nsIDNSRecord *record, nsresult status) { |
|
186 ASSERT_ON_THREAD(thread_); |
|
187 // First check if we've been canceled. This is single-threaded on the STS |
|
188 // thread, but cancel() cannot guarantee this event isn't on the queue. |
|
189 if (!canceled_) { |
|
190 nr_transport_addr *cb_addr = nullptr; |
|
191 nr_transport_addr ta; |
|
192 // TODO(jib@mozilla.com): Revisit when we do TURN. |
|
193 if (NS_SUCCEEDED(status)) { |
|
194 net::NetAddr na; |
|
195 if (NS_SUCCEEDED(record->GetNextAddr(port_, &na))) { |
|
196 MOZ_ALWAYS_TRUE (nr_netaddr_to_transport_addr(&na, &ta, |
|
197 transport_) == 0); |
|
198 cb_addr = &ta; |
|
199 } |
|
200 } |
|
201 cb_(cb_arg_, cb_addr); |
|
202 Release(); |
|
203 } |
|
204 return NS_OK; |
|
205 } |
|
206 |
|
207 int NrIceResolver::cancel(void *obj, void *handle) { |
|
208 MOZ_ALWAYS_TRUE(obj); |
|
209 MOZ_ASSERT(handle); |
|
210 ASSERT_ON_THREAD(static_cast<NrIceResolver *>(obj)->sts_thread_); |
|
211 return static_cast<PendingResolution *>(handle)->cancel(); |
|
212 } |
|
213 |
|
214 int NrIceResolver::PendingResolution::cancel() { |
|
215 request_->Cancel (NS_ERROR_ABORT); |
|
216 canceled_ = true; // in case OnLookupComplete is already on event queue. |
|
217 Release(); |
|
218 return 0; |
|
219 } |
|
220 |
|
221 NS_IMPL_ISUPPORTS(NrIceResolver::PendingResolution, nsIDNSListener); |
|
222 } // End of namespace mozilla |