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