1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <Ice/IPEndpointI.h>
6 #include <Ice/ProtocolInstance.h>
7 #include <Ice/Instance.h>
8 #include <Ice/LocalException.h>
9 #include <Ice/PropertiesI.h>
10 #include <Ice/LoggerUtil.h>
11 #include <Ice/HashUtil.h>
12 #include <Ice/NetworkProxy.h>
13 #include <IceUtil/MutexPtrLock.h>
14 
15 using namespace std;
16 using namespace Ice;
17 using namespace Ice::Instrumentation;
18 using namespace IceInternal;
19 
20 namespace
21 {
22 
23 IceUtil::Mutex* hashMutex = 0;
24 
25 class Init
26 {
27 public:
28 
Init()29     Init()
30     {
31         hashMutex = new IceUtil::Mutex;
32     }
33 
~Init()34     ~Init()
35     {
36         delete hashMutex;
37         hashMutex = 0;
38     }
39 };
40 
41 Init init;
42 
43 }
44 
45 #ifndef ICE_CPP11_MAPPING
upCast(IPEndpointI * p)46 IceUtil::Shared* IceInternal::upCast(IPEndpointI* p) { return p; }
47 #endif
upCast(EndpointHostResolver * p)48 IceUtil::Shared* IceInternal::upCast(EndpointHostResolver* p) { return p; }
49 
IPEndpointInfoI(const EndpointIPtr & endpoint)50 IceInternal::IPEndpointInfoI::IPEndpointInfoI(const EndpointIPtr& endpoint) : _endpoint(endpoint)
51 {
52 }
53 
~IPEndpointInfoI()54 IceInternal::IPEndpointInfoI::~IPEndpointInfoI()
55 {
56 }
57 
58 Ice::Short
type() const59 IceInternal::IPEndpointInfoI::type() const ICE_NOEXCEPT
60 {
61     return _endpoint->type();
62 }
63 
64 bool
datagram() const65 IceInternal::IPEndpointInfoI::datagram() const ICE_NOEXCEPT
66 {
67     return _endpoint->datagram();
68 }
69 
70 bool
secure() const71 IceInternal::IPEndpointInfoI::secure() const ICE_NOEXCEPT
72 {
73     return _endpoint->secure();
74 }
75 
76 Ice::EndpointInfoPtr
getInfo() const77 IceInternal::IPEndpointI::getInfo() const ICE_NOEXCEPT
78 {
79     Ice::IPEndpointInfoPtr info = ICE_MAKE_SHARED(IPEndpointInfoI, ICE_SHARED_FROM_CONST_THIS(IPEndpointI));
80     fillEndpointInfo(info.get());
81     return info;
82 }
83 
84 Ice::Short
type() const85 IceInternal::IPEndpointI::type() const
86 {
87     return _instance->type();
88 }
89 
90 const string&
protocol() const91 IceInternal::IPEndpointI::protocol() const
92 {
93     return _instance->protocol();
94 }
95 
96 bool
secure() const97 IceInternal::IPEndpointI::secure() const
98 {
99     return _instance->secure();
100 }
101 
102 void
streamWriteImpl(OutputStream * s) const103 IceInternal::IPEndpointI::streamWriteImpl(OutputStream* s) const
104 {
105     s->write(_host, false);
106     s->write(_port);
107 }
108 
109 const string&
connectionId() const110 IceInternal::IPEndpointI::connectionId() const
111 {
112     return _connectionId;
113 }
114 
115 EndpointIPtr
connectionId(const string & connectionId) const116 IceInternal::IPEndpointI::connectionId(const string& connectionId) const
117 {
118     if(connectionId == _connectionId)
119     {
120         return ICE_SHARED_FROM_CONST_THIS(IPEndpointI);
121     }
122     else
123     {
124         return createEndpoint(_host, _port, connectionId);
125     }
126 }
127 
128 void
connectors_async(Ice::EndpointSelectionType selType,const EndpointI_connectorsPtr & cb) const129 IceInternal::IPEndpointI::connectors_async(Ice::EndpointSelectionType selType, const EndpointI_connectorsPtr& cb) const
130 {
131     _instance->resolve(_host, _port, selType, ICE_SHARED_FROM_CONST_THIS(IPEndpointI), cb);
132 }
133 
134 vector<EndpointIPtr>
expandIfWildcard() const135 IceInternal::IPEndpointI::expandIfWildcard() const
136 {
137     vector<EndpointIPtr> endps;
138     vector<string> hosts = getHostsForEndpointExpand(_host, _instance->protocolSupport(), false);
139     if(hosts.empty())
140     {
141         endps.push_back(ICE_SHARED_FROM_CONST_THIS(IPEndpointI));
142     }
143     else
144     {
145         for(vector<string>::const_iterator p = hosts.begin(); p != hosts.end(); ++p)
146         {
147             endps.push_back(createEndpoint(*p, _port, _connectionId));
148         }
149     }
150     return endps;
151 }
152 
153 vector<EndpointIPtr>
expandHost(EndpointIPtr & publish) const154 IceInternal::IPEndpointI::expandHost(EndpointIPtr& publish) const
155 {
156     //
157     // If this endpoint has an empty host (wildcard address), don't expand, just return
158     // this endpoint.
159     //
160     if(_host.empty())
161     {
162         vector<EndpointIPtr> endpoints;
163         endpoints.push_back(ICE_SHARED_FROM_CONST_THIS(IPEndpointI));
164         return endpoints;
165     }
166 
167     //
168     // If using a fixed port, this endpoint can be used as the published endpoint to
169     // access the returned endpoints. Otherwise, we'll publish each individual expanded
170     // endpoint.
171     //
172     if(_port > 0)
173     {
174         publish = ICE_SHARED_FROM_CONST_THIS(IPEndpointI);
175     }
176 
177     vector<Address> addrs = getAddresses(_host,
178                                          _port,
179                                          _instance->protocolSupport(),
180                                          Ice::ICE_ENUM(EndpointSelectionType, Ordered),
181                                          _instance->preferIPv6(),
182                                          true);
183 
184     vector<EndpointIPtr> endpoints;
185     if(addrs.size() == 1)
186     {
187         endpoints.push_back(ICE_SHARED_FROM_CONST_THIS(IPEndpointI));
188     }
189     else
190     {
191         for(vector<Address>::const_iterator p = addrs.begin(); p != addrs.end(); ++p)
192         {
193             string host;
194             int port;
195             addrToAddressAndPort(*p, host, port);
196             endpoints.push_back(createEndpoint(host, port, _connectionId));
197         }
198     }
199     return endpoints;
200 }
201 
202 bool
equivalent(const EndpointIPtr & endpoint) const203 IceInternal::IPEndpointI::equivalent(const EndpointIPtr& endpoint) const
204 {
205     const IPEndpointI* ipEndpointI = dynamic_cast<const IPEndpointI*>(endpoint.get());
206     if(!ipEndpointI)
207     {
208         return false;
209     }
210     return ipEndpointI->type() == type() && ipEndpointI->_host == _host && ipEndpointI->_port == _port;
211 }
212 
213 Ice::Int
hash() const214 IceInternal::IPEndpointI::hash() const
215 {
216     IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(hashMutex);
217     if(!_hashInitialized)
218     {
219         _hashValue = 5381;
220         hashAdd(_hashValue, type());
221         hashInit(_hashValue);
222         _hashInitialized = true;
223     }
224     return _hashValue;
225 }
226 
227 string
options() const228 IceInternal::IPEndpointI::options() const
229 {
230     //
231     // WARNING: Certain features, such as proxy validation in Glacier2,
232     // depend on the format of proxy strings. Changes to toString() and
233     // methods called to generate parts of the reference string could break
234     // these features. Please review for all features that depend on the
235     // format of proxyToString() before changing this and related code.
236     //
237     ostringstream s;
238 
239     if(!_host.empty())
240     {
241         s << " -h ";
242         bool addQuote = _host.find(':') != string::npos;
243         if(addQuote)
244         {
245             s << "\"";
246         }
247         s << _host;
248         if(addQuote)
249         {
250             s << "\"";
251         }
252     }
253 
254     s << " -p " << _port;
255 
256     if(isAddressValid(_sourceAddr))
257     {
258         s << " --sourceAddress " << inetAddrToString(_sourceAddr);
259     }
260 
261     return s.str();
262 }
263 
264 bool
265 #ifdef ICE_CPP11_MAPPING
operator ==(const Endpoint & r) const266 IceInternal::IPEndpointI::operator==(const Endpoint& r) const
267 #else
268 IceInternal::IPEndpointI::operator==(const LocalObject& r) const
269 #endif
270 {
271     const IPEndpointI* p = dynamic_cast<const IPEndpointI*>(&r);
272     if(!p)
273     {
274         return false;
275     }
276 
277     if(this == p)
278     {
279         return true;
280     }
281 
282     if(_host != p->_host)
283     {
284         return false;
285     }
286 
287     if(_port != p->_port)
288     {
289         return false;
290     }
291 
292     if(_connectionId != p->_connectionId)
293     {
294         return false;
295     }
296 
297     if(compareAddress(_sourceAddr, p->_sourceAddr) != 0)
298     {
299         return false;
300     }
301     return true;
302 }
303 
304 bool
305 #ifdef ICE_CPP11_MAPPING
operator <(const Endpoint & r) const306 IceInternal::IPEndpointI::operator<(const Endpoint& r) const
307 #else
308 IceInternal::IPEndpointI::operator<(const LocalObject& r) const
309 #endif
310 {
311     const IPEndpointI* p = dynamic_cast<const IPEndpointI*>(&r);
312     if(!p)
313     {
314         const EndpointI* e = dynamic_cast<const EndpointI*>(&r);
315         if(!e)
316         {
317             return false;
318         }
319         return type() < e->type();
320     }
321 
322     if(this == p)
323     {
324         return false;
325     }
326 
327     if(type() < p->type())
328     {
329         return true;
330     }
331     else if(p->type() < type())
332     {
333         return false;
334     }
335 
336     if(_host < p->_host)
337     {
338         return true;
339     }
340     else if(p->_host < _host)
341     {
342         return false;
343     }
344 
345     if(_port < p->_port)
346     {
347         return true;
348     }
349     else if(p->_port < _port)
350     {
351         return false;
352     }
353 
354     if(_connectionId < p->_connectionId)
355     {
356         return true;
357     }
358     else if(p->_connectionId < _connectionId)
359     {
360         return false;
361     }
362 
363     int rc = compareAddress(_sourceAddr, p->_sourceAddr);
364     if(rc < 0)
365     {
366         return true;
367     }
368     else if(rc > 0)
369     {
370         return false;
371     }
372 
373     return false;
374 }
375 
376 vector<ConnectorPtr>
connectors(const vector<Address> & addresses,const NetworkProxyPtr & proxy) const377 IceInternal::IPEndpointI::connectors(const vector<Address>& addresses, const NetworkProxyPtr& proxy) const
378 {
379     vector<ConnectorPtr> connectors;
380     for(unsigned int i = 0; i < addresses.size(); ++i)
381     {
382         connectors.push_back(createConnector(addresses[i], proxy));
383     }
384     return connectors;
385 }
386 
387 void
hashInit(Ice::Int & h) const388 IceInternal::IPEndpointI::hashInit(Ice::Int& h) const
389 {
390     hashAdd(h, _host);
391     hashAdd(h, _port);
392     hashAdd(h, _connectionId);
393     if(isAddressValid(_sourceAddr))
394     {
395         hashAdd(h, inetAddrToString(_sourceAddr));
396     }
397 }
398 
399 void
fillEndpointInfo(Ice::IPEndpointInfo * info) const400 IceInternal::IPEndpointI::fillEndpointInfo(Ice::IPEndpointInfo* info) const
401 {
402     info->host = _host;
403     info->port = _port;
404     info->sourceAddress = inetAddrToString(_sourceAddr);
405 }
406 
407 void
initWithOptions(vector<string> & args,bool oaEndpoint)408 IceInternal::IPEndpointI::initWithOptions(vector<string>& args, bool oaEndpoint)
409 {
410     EndpointI::initWithOptions(args);
411 
412     if(_host.empty())
413     {
414         const_cast<string&>(_host) = _instance->defaultHost();
415     }
416     else if(_host == "*")
417     {
418         if(oaEndpoint)
419         {
420             const_cast<string&>(_host) = string();
421         }
422         else
423         {
424             throw Ice::EndpointParseException(__FILE__, __LINE__, "`-h *' not valid for proxy endpoint `" + toString() +
425                                               "'");
426         }
427     }
428 
429     if(isAddressValid(_sourceAddr))
430     {
431         if(oaEndpoint)
432         {
433             throw Ice::EndpointParseException(__FILE__, __LINE__,
434                                               "`--sourceAddress' not valid for object adapter endpoint `" + toString() +
435                                               "'");
436         }
437     }
438     else if(!oaEndpoint)
439     {
440         const_cast<Address&>(_sourceAddr) = _instance->defaultSourceAddress();
441     }
442 }
443 
444 bool
checkOption(const string & option,const string & argument,const string & endpoint)445 IceInternal::IPEndpointI::checkOption(const string& option, const string& argument, const string& endpoint)
446 {
447     if(option == "-h")
448     {
449         if(argument.empty())
450         {
451             throw Ice::EndpointParseException(__FILE__, __LINE__, "no argument provided for -h option in endpoint " +
452                                               endpoint);
453         }
454         const_cast<string&>(_host) = argument;
455     }
456     else if(option == "-p")
457     {
458         if(argument.empty())
459         {
460             throw Ice::EndpointParseException(__FILE__, __LINE__, "no argument provided for -p option in endpoint " +
461                                               endpoint);
462         }
463         istringstream p(argument);
464         if(!(p >> const_cast<Ice::Int&>(_port)) || !p.eof())
465         {
466             throw Ice::EndpointParseException(__FILE__, __LINE__, "invalid port value `" + argument + "' in endpoint " +
467                                               endpoint);
468         }
469         else if(_port < 0 || _port > 65535)
470         {
471             throw Ice::EndpointParseException(__FILE__, __LINE__, "port value `" + argument +
472                                               "' out of range in endpoint " + endpoint);
473         }
474     }
475     else if(option == "--sourceAddress")
476     {
477         if(argument.empty())
478         {
479             throw Ice::EndpointParseException(__FILE__, __LINE__,
480                                               "no argument provided for --sourceAddress option in endpoint " +
481                                               endpoint);
482         }
483 #ifndef ICE_OS_UWP
484         const_cast<Address&>(_sourceAddr) = getNumericAddress(argument);
485         if(!isAddressValid(_sourceAddr))
486         {
487             throw Ice::EndpointParseException(__FILE__, __LINE__,
488                                               "invalid IP address provided for --sourceAddress option in endpoint " +
489                                               endpoint);
490         }
491 #endif
492     }
493     else
494     {
495         return false;
496     }
497     return true;
498 }
499 
IPEndpointI(const ProtocolInstancePtr & instance,const string & host,int port,const Address & sourceAddr,const string & connectionId)500 IceInternal::IPEndpointI::IPEndpointI(const ProtocolInstancePtr& instance, const string& host, int port,
501                                       const Address& sourceAddr, const string& connectionId) :
502     _instance(instance),
503     _host(host),
504     _port(port),
505     _sourceAddr(sourceAddr),
506     _connectionId(connectionId),
507     _hashInitialized(false)
508 {
509 }
510 
IPEndpointI(const ProtocolInstancePtr & instance)511 IceInternal::IPEndpointI::IPEndpointI(const ProtocolInstancePtr& instance) :
512     _instance(instance),
513     _port(0),
514     _hashInitialized(false)
515 {
516 }
517 
IPEndpointI(const ProtocolInstancePtr & instance,InputStream * s)518 IceInternal::IPEndpointI::IPEndpointI(const ProtocolInstancePtr& instance, InputStream* s) :
519     _instance(instance),
520     _port(0),
521     _hashInitialized(false)
522 {
523     s->read(const_cast<string&>(_host), false);
524     s->read(const_cast<Ice::Int&>(_port));
525 }
526 
527 #ifndef ICE_OS_UWP
528 
EndpointHostResolver(const InstancePtr & instance)529 IceInternal::EndpointHostResolver::EndpointHostResolver(const InstancePtr& instance) :
530     IceUtil::Thread("Ice.HostResolver"),
531     _instance(instance),
532     _protocol(instance->protocolSupport()),
533     _preferIPv6(instance->preferIPv6()),
534     _destroyed(false)
535 {
536     updateObserver();
537 }
538 
539 void
resolve(const string & host,int port,Ice::EndpointSelectionType selType,const IPEndpointIPtr & endpoint,const EndpointI_connectorsPtr & callback)540 IceInternal::EndpointHostResolver::resolve(const string& host, int port, Ice::EndpointSelectionType selType,
541                                            const IPEndpointIPtr& endpoint, const EndpointI_connectorsPtr& callback)
542 {
543     //
544     // Try to get the addresses without DNS lookup. If this doesn't work, we queue a resolve
545     // entry and the thread will take care of getting the endpoint addresses.
546     //
547     NetworkProxyPtr networkProxy = _instance->networkProxy();
548     if(!networkProxy)
549     {
550         try
551         {
552             vector<Address> addrs = getAddresses(host, port, _protocol, selType, _preferIPv6, false);
553             if(!addrs.empty())
554             {
555                 callback->connectors(endpoint->connectors(addrs, 0));
556                 return;
557             }
558         }
559         catch(const Ice::LocalException& ex)
560         {
561             callback->exception(ex);
562             return;
563         }
564     }
565 
566     Lock sync(*this);
567     assert(!_destroyed);
568 
569     ResolveEntry entry;
570     entry.host = host;
571     entry.port = port;
572     entry.selType = selType;
573     entry.endpoint = endpoint;
574     entry.callback = callback;
575 
576     const CommunicatorObserverPtr& obsv = _instance->initializationData().observer;
577     if(obsv)
578     {
579         entry.observer = obsv->getEndpointLookupObserver(endpoint);
580         if(entry.observer)
581         {
582             entry.observer->attach();
583         }
584     }
585 
586     _queue.push_back(entry);
587     notify();
588 }
589 
590 void
destroy()591 IceInternal::EndpointHostResolver::destroy()
592 {
593     Lock sync(*this);
594     assert(!_destroyed);
595     _destroyed = true;
596     notify();
597 }
598 
599 void
run()600 IceInternal::EndpointHostResolver::run()
601 {
602     while(true)
603     {
604         ResolveEntry r;
605         ThreadObserverPtr threadObserver;
606         {
607             Lock sync(*this);
608             while(!_destroyed && _queue.empty())
609             {
610                 wait();
611             }
612 
613             if(_destroyed)
614             {
615                 break;
616             }
617 
618             r = _queue.front();
619             _queue.pop_front();
620             threadObserver = _observer.get();
621         }
622 
623         if(threadObserver)
624         {
625             threadObserver->stateChanged(ICE_ENUM(ThreadState, ThreadStateIdle), ICE_ENUM(ThreadState, ThreadStateInUseForOther));
626         }
627 
628         try
629         {
630             NetworkProxyPtr networkProxy = _instance->networkProxy();
631             ProtocolSupport protocol = _protocol;
632             if(networkProxy)
633             {
634                 networkProxy = networkProxy->resolveHost(_protocol);
635                 if(networkProxy)
636                 {
637                     protocol = networkProxy->getProtocolSupport();
638                 }
639             }
640 
641             vector<Address> addresses = getAddresses(r.host, r.port, protocol, r.selType, _preferIPv6, true);
642             if(r.observer)
643             {
644                 r.observer->detach();
645                 r.observer = 0;
646             }
647 
648             r.callback->connectors(r.endpoint->connectors(addresses, networkProxy));
649 
650             if(threadObserver)
651             {
652                 threadObserver->stateChanged(ICE_ENUM(ThreadState, ThreadStateInUseForOther),
653                                              ICE_ENUM(ThreadState, ThreadStateIdle));
654             }
655 
656         }
657         catch(const Ice::LocalException& ex)
658         {
659             if(threadObserver)
660             {
661                 threadObserver->stateChanged(ICE_ENUM(ThreadState, ThreadStateInUseForOther),
662                                              ICE_ENUM(ThreadState, ThreadStateIdle));
663             }
664             if(r.observer)
665             {
666                 r.observer->failed(ex.ice_id());
667                 r.observer->detach();
668             }
669             r.callback->exception(ex);
670         }
671     }
672 
673     for(deque<ResolveEntry>::const_iterator p = _queue.begin(); p != _queue.end(); ++p)
674     {
675         Ice::CommunicatorDestroyedException ex(__FILE__, __LINE__);
676         if(p->observer)
677         {
678             p->observer->failed(ex.ice_id());
679             p->observer->detach();
680         }
681         p->callback->exception(ex);
682     }
683     _queue.clear();
684 
685     if(_observer)
686     {
687         _observer.detach();
688     }
689 }
690 
691 void
updateObserver()692 IceInternal::EndpointHostResolver::updateObserver()
693 {
694     Lock sync(*this);
695     const CommunicatorObserverPtr& obsv = _instance->initializationData().observer;
696     if(obsv)
697     {
698         _observer.attach(obsv->getThreadObserver("Communicator",
699                                                  name(),
700                                                  ICE_ENUM(ThreadState, ThreadStateIdle),
701                                                  _observer.get()));
702     }
703 }
704 
705 #else
706 
EndpointHostResolver(const InstancePtr & instance)707 IceInternal::EndpointHostResolver::EndpointHostResolver(const InstancePtr& instance) :
708     _instance(instance)
709 {
710 }
711 
712 void
resolve(const string & host,int port,Ice::EndpointSelectionType selType,const IPEndpointIPtr & endpoint,const EndpointI_connectorsPtr & callback)713 IceInternal::EndpointHostResolver::resolve(const string& host,
714                                            int port,
715                                            Ice::EndpointSelectionType selType,
716                                            const IPEndpointIPtr& endpoint,
717                                            const EndpointI_connectorsPtr& callback)
718 {
719     //
720     // No DNS lookup support with UWP.
721     //
722     callback->connectors(endpoint->connectors(getAddresses(host, port,
723                                                            _instance->protocolSupport(),
724                                                            selType,
725                                                            _instance->preferIPv6(),
726                                                            false),
727                                               _instance->networkProxy()));
728 }
729 
730 void
destroy()731 IceInternal::EndpointHostResolver::destroy()
732 {
733 }
734 
735 void
run()736 IceInternal::EndpointHostResolver::run()
737 {
738 }
739 
740 void
updateObserver()741 IceInternal::EndpointHostResolver::updateObserver()
742 {
743 }
744 
745 #endif
746