1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 namespace IceInternal
6 {
7     using System.Collections.Generic;
8     using System.Diagnostics;
9     using System.Net;
10     using System.Threading;
11 
12     public class EndpointHostResolver
13     {
EndpointHostResolver(Instance instance)14         internal EndpointHostResolver(Instance instance)
15         {
16             _instance = instance;
17             _protocol = instance.protocolSupport();
18             _preferIPv6 = instance.preferIPv6();
19             _thread = new HelperThread(this);
20             updateObserver();
21             _thread.Start(Util.stringToThreadPriority(
22                     instance.initializationData().properties.getProperty("Ice.ThreadPriority")));
23         }
24 
resolve(string host, int port, Ice.EndpointSelectionType selType, IPEndpointI endpoint, EndpointI_connectors callback)25         public void resolve(string host, int port, Ice.EndpointSelectionType selType, IPEndpointI endpoint,
26                             EndpointI_connectors callback)
27         {
28             //
29             // Try to get the addresses without DNS lookup. If this doesn't work, we queue a resolve
30             // entry and the thread will take care of getting the endpoint addresses.
31             //
32             NetworkProxy networkProxy = _instance.networkProxy();
33             if(networkProxy == null)
34             {
35                 try
36                 {
37                     List<EndPoint> addrs = Network.getAddresses(host, port, _protocol, selType, _preferIPv6, false);
38                     if(addrs.Count > 0)
39                     {
40                         callback.connectors(endpoint.connectors(addrs, null));
41                         return;
42                     }
43                 }
44                 catch(Ice.LocalException ex)
45                 {
46                     callback.exception(ex);
47                     return;
48                 }
49             }
50 
51             lock(this)
52             {
53                 Debug.Assert(!_destroyed);
54 
55                 ResolveEntry entry = new ResolveEntry();
56                 entry.host = host;
57                 entry.port = port;
58                 entry.selType = selType;
59                 entry.endpoint = endpoint;
60                 entry.callback = callback;
61 
62                 Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer;
63                 if(obsv != null)
64                 {
65                     entry.observer = obsv.getEndpointLookupObserver(endpoint);
66                     if(entry.observer != null)
67                     {
68                         entry.observer.attach();
69                     }
70                 }
71 
72                 _queue.AddLast(entry);
73                 Monitor.Pulse(this);
74             }
75         }
76 
destroy()77         public void destroy()
78         {
79             lock(this)
80             {
81                 Debug.Assert(!_destroyed);
82                 _destroyed = true;
83                 Monitor.Pulse(this);
84             }
85         }
86 
joinWithThread()87         public void joinWithThread()
88         {
89             if(_thread != null)
90             {
91                 _thread.Join();
92             }
93         }
94 
run()95         public void run()
96         {
97             while(true)
98             {
99                 ResolveEntry r;
100                 Ice.Instrumentation.ThreadObserver threadObserver;
101 
102                 lock(this)
103                 {
104                     while(!_destroyed && _queue.Count == 0)
105                     {
106                         Monitor.Wait(this);
107                     }
108 
109                     if(_destroyed)
110                     {
111                         break;
112                     }
113 
114                     r = _queue.First.Value;
115                     _queue.RemoveFirst();
116                     threadObserver = _observer;
117                 }
118 
119                 if(threadObserver != null)
120                 {
121                     threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateIdle,
122                                                 Ice.Instrumentation.ThreadState.ThreadStateInUseForOther);
123                 }
124 
125                 try
126                 {
127 
128                     NetworkProxy networkProxy = _instance.networkProxy();
129                     int protocol = _protocol;
130                     if(networkProxy != null)
131                     {
132                         networkProxy = networkProxy.resolveHost(protocol);
133                         if(networkProxy != null)
134                         {
135                             protocol = networkProxy.getProtocolSupport();
136                         }
137                     }
138 
139                     List<EndPoint> addrs = Network.getAddresses(r.host, r.port, protocol, r.selType, _preferIPv6, true);
140                     if(r.observer != null)
141                     {
142                         r.observer.detach();
143                         r.observer = null;
144                     }
145 
146                     r.callback.connectors(r.endpoint.connectors(addrs, networkProxy));
147                 }
148                 catch(Ice.LocalException ex)
149                 {
150                     if(r.observer != null)
151                     {
152                         r.observer.failed(ex.ice_id());
153                         r.observer.detach();
154                     }
155                     r.callback.exception(ex);
156                 }
157                 finally
158                 {
159                     if(threadObserver != null)
160                     {
161                         threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateInUseForOther,
162                                                     Ice.Instrumentation.ThreadState.ThreadStateIdle);
163                     }
164                 }
165             }
166 
167             foreach(ResolveEntry entry in _queue)
168             {
169                 Ice.CommunicatorDestroyedException ex = new Ice.CommunicatorDestroyedException();
170                 if(entry.observer != null)
171                 {
172                     entry.observer.failed(ex.ice_id());
173                     entry.observer.detach();
174                 }
175                 entry.callback.exception(ex);
176             }
177             _queue.Clear();
178 
179             if(_observer != null)
180             {
181                 _observer.detach();
182             }
183         }
184 
185         public void
updateObserver()186         updateObserver()
187         {
188             lock(this)
189             {
190                 Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer;
191                 if(obsv != null)
192                 {
193                     _observer = obsv.getThreadObserver("Communicator",
194                                                        _thread.getName(),
195                                                        Ice.Instrumentation.ThreadState.ThreadStateIdle,
196                                                        _observer);
197                     if(_observer != null)
198                     {
199                         _observer.attach();
200                     }
201                 }
202             }
203         }
204 
205         private class ResolveEntry
206         {
207             internal string host;
208             internal int port;
209             internal Ice.EndpointSelectionType selType;
210             internal IPEndpointI endpoint;
211             internal EndpointI_connectors callback;
212             internal Ice.Instrumentation.Observer observer;
213         }
214 
215         private readonly Instance _instance;
216         private readonly int _protocol;
217         private readonly bool _preferIPv6;
218         private bool _destroyed;
219         private LinkedList<ResolveEntry> _queue = new LinkedList<ResolveEntry>();
220         private Ice.Instrumentation.ThreadObserver _observer;
221 
222         private sealed class HelperThread
223         {
HelperThread(EndpointHostResolver resolver)224             internal HelperThread(EndpointHostResolver resolver)
225             {
226                 _resolver = resolver;
227                 _name = _resolver._instance.initializationData().properties.getProperty("Ice.ProgramName");
228                 if(_name.Length > 0)
229                 {
230                     _name += "-";
231                 }
232                 _name += "Ice.HostResolver";
233             }
234 
Join()235             public void Join()
236             {
237                 _thread.Join();
238             }
239 
Start(ThreadPriority priority)240             public void Start(ThreadPriority priority)
241             {
242                 _thread = new Thread(new ThreadStart(Run));
243                 _thread.IsBackground = true;
244                 _thread.Name = _name;
245                 _thread.Priority = priority;
246                 _thread.Start();
247             }
248 
Run()249             public void Run()
250             {
251                 try
252                 {
253                     _resolver.run();
254                 }
255                 catch(System.Exception ex)
256                 {
257                     string s = "exception in endpoint host resolver thread " + _name + ":\n" + ex;
258                     _resolver._instance.initializationData().logger.error(s);
259                 }
260             }
261 
getName()262             public string getName()
263             {
264                 return _name;
265             }
266 
267             private EndpointHostResolver _resolver;
268             private string _name;
269             private Thread _thread;
270         }
271 
272         private HelperThread _thread;
273     }
274 }
275