@@ -125,33 +125,49 @@ impl Resolver {
125125 /// The set of addresses may not be deterministic, because the
126126 /// implementation of the resolver may race multiple DNS requests.
127127 pub async fn resolve ( & self , name : & ngx_str_t , pool : & Pool ) -> Res {
128- let ctx = unsafe {
129- NonNull :: new ( ngx_resolve_start (
130- self . resolver . as_ptr ( ) ,
131- core:: ptr:: null_mut ( ) ,
132- ) )
133- . ok_or ( Error :: AllocationFailed ) ?
134- } ;
135-
136- let mut resolver = Resolution :: new ( name, pool, self . timeout , ctx) ?;
128+ let mut resolver = Resolution :: new ( name, pool, self . resolver , self . timeout ) ?;
137129 resolver. as_mut ( ) . await
138130 }
139131}
140132
141133struct Resolution < ' a > {
134+ // Storage for the result of the resolution `Res`. Populated by the
135+ // callback handler, and taken by the Future::poll impl.
142136 complete : Option < Res > ,
137+ // Storage for a pending Waker. Populated by the Future::poll impl,
138+ // and taken by the callback handler.
143139 waker : Option < Waker > ,
140+ // Pool used for allocating `Vec<ngx_addr_t>` contents in `Res`. Read by
141+ // the callback handler.
144142 pool : & ' a Pool ,
143+ // Pointer to the ngx_resolver_ctx_t. Resolution constructs this with
144+ // ngx_resolver_name_start in the constructor, and is responsible for
145+ // freeing it, with ngx_resolver_name_done, once it is no longer needed -
146+ // this happens in either the callback handler, or the drop impl. Calling
147+ // ngx_resolver_name_done before the callback fires ensure nginx does not
148+ // ever call the callback.
145149 ctx : Option < NonNull < ngx_resolver_ctx_t > > ,
146150}
147151
148152impl < ' a > Resolution < ' a > {
149153 fn new (
150154 name : & ngx_str_t ,
151155 pool : & ' a Pool ,
156+ resolver : NonNull < ngx_resolver_t > ,
152157 timeout : ngx_msec_t ,
153- mut ctx : NonNull < ngx_resolver_ctx_t > ,
154158 ) -> Result < Pin < Box < Self > > , Error > {
159+ let mut ctx = unsafe {
160+ // Start a new resolver context. This implementation currently
161+ // passes a null for the second argument `temp`. A non-null `temp`
162+ // provides a fast, non-callback-based path for immediately
163+ // returning an addr iff `temp` contains a name which is textual
164+ // form of an addr.
165+ let ctx = ngx_resolve_start ( resolver. as_ptr ( ) , core:: ptr:: null_mut ( ) ) ;
166+ NonNull :: new ( ctx) . ok_or ( Error :: AllocationFailed ) ?
167+ } ;
168+
169+ // Create a pinned Resolution on the heap, so that we can make
170+ // a stable pointer to the Resolution struct.
155171 let mut this = Pin :: new ( Box :: new ( Resolution {
156172 complete : None ,
157173 waker : None ,
@@ -160,15 +176,26 @@ impl<'a> Resolution<'a> {
160176 } ) ) ;
161177
162178 {
179+ // Set up the ctx with everything the resolver needs to resolve a
180+ // name, and the handler callback which is called on completion.
163181 let ctx: & mut ngx_resolver_ctx_t = unsafe { ctx. as_mut ( ) } ;
164182 ctx. name = * name;
165183 ctx. timeout = timeout;
166184 ctx. set_cancelable ( 1 ) ;
167185 ctx. handler = Some ( Self :: handler) ;
186+ // Safety: Self::handler, Future::poll, and Drop::drop will have
187+ // access to &mut Resolution. Nginx is single-threaded and we are
188+ // assured only one of those is on the stack at a time, except if
189+ // Self::handler wakes a task which polls or drops the Future,
190+ // which it only does after use of &mut Resolution is complete.
168191 let ptr: & mut Resolution = unsafe { Pin :: into_inner_unchecked ( this. as_mut ( ) ) } ;
169192 ctx. data = ptr as * mut Resolution as * mut c_void ;
170193 }
171194
195+ // Start name resolution using the ctx. If the name is in the dns
196+ // cache, the handler may get called from this stack. Otherwise, it
197+ // will be called later by nginx when it gets a dns response or a
198+ // timeout.
172199 let ret = unsafe { ngx_resolve_name ( ctx. as_ptr ( ) ) } ;
173200 if ret != 0 {
174201 return Err ( Error :: Resolver (
@@ -180,18 +207,26 @@ impl<'a> Resolution<'a> {
180207 Ok ( this)
181208 }
182209
210+ // Nginx will call this handler when name resolution completes. If the
211+ // result is cached, this could be
183212 unsafe extern "C" fn handler ( ctx : * mut ngx_resolver_ctx_t ) {
184213 let mut data = unsafe { NonNull :: new_unchecked ( ( * ctx) . data as * mut Resolution ) } ;
185214 let this: & mut Resolution = unsafe { data. as_mut ( ) } ;
186215 this. complete = Some ( Self :: resolve_result ( ctx, this. pool ) ) ;
187- this. ctx . take ( ) ;
216+
217+ let mut ctx = this. ctx . take ( ) . expect ( "ctx must be present" ) ;
218+ unsafe { nginx_sys:: ngx_resolve_name_done ( ctx. as_mut ( ) ) } ;
219+
220+ // Wake last, after all use of &mut Resolution, because wake may
221+ // poll Resolution future on current stack.
188222 if let Some ( waker) = this. waker . take ( ) {
189- // Wake last, after all use of &mut Resolution, because wake may
190- // poll Resolution future on current stack.
191223 waker. wake ( ) ;
192224 }
193225 }
194226
227+ /// Take the results in a ctx and make an owned copy as a
228+ /// Result<Vec<ngx_addr_t>, Error>, where both the Vec and internals of
229+ /// the ngx_addr_t are allocated on the given Pool
195230 fn resolve_result ( ctx : * mut ngx_resolver_ctx_t , pool : & Pool ) -> Res {
196231 let ctx = unsafe { ctx. as_ref ( ) . unwrap ( ) } ;
197232 let s = ctx. state ;
@@ -211,6 +246,8 @@ impl<'a> Resolution<'a> {
211246 Ok ( out)
212247 }
213248
249+ /// Take the contents of an ngx_resolver_addr_t and make an owned copy as
250+ /// an ngx_addr_t, using the Pool for allocation of the internals.
214251 fn copy_resolved_addr (
215252 addr : * mut nginx_sys:: ngx_resolver_addr_t ,
216253 pool : & Pool ,
@@ -247,9 +284,12 @@ impl<'a> core::future::Future for Resolution<'a> {
247284 type Output = Result < Vec < ngx_addr_t > , Error > ;
248285 fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
249286 let mut this = self . as_mut ( ) ;
287+ // The handler populates this.complete, and we consume it here:
250288 match this. complete . take ( ) {
251289 Some ( res) => Poll :: Ready ( res) ,
252290 None => {
291+ // If the handler has not yet fired, populate the waker field,
292+ // which the handler will consume:
253293 match & mut self . waker {
254294 None => {
255295 self . waker = Some ( cx. waker ( ) . clone ( ) ) ;
@@ -264,6 +304,9 @@ impl<'a> core::future::Future for Resolution<'a> {
264304
265305impl < ' a > Drop for Resolution < ' a > {
266306 fn drop ( & mut self ) {
307+ // ctx is taken and freed if the Resolution reaches the handler
308+ // callback, but if dropped before that callback, this will cancel any
309+ // ongoing work as well as free the ctx memory.
267310 if let Some ( mut ctx) = self . ctx . take ( ) {
268311 unsafe {
269312 nginx_sys:: ngx_resolve_name_done ( ctx. as_mut ( ) ) ;
0 commit comments