1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <IceBT/EndpointI.h>
6 #include <IceBT/AcceptorI.h>
7 #include <IceBT/ConnectorI.h>
8 #include <IceBT/Engine.h>
9 #include <IceBT/Instance.h>
10 #include <IceBT/Util.h>
11 
12 #include <Ice/LocalException.h>
13 #include <Ice/DefaultsAndOverrides.h>
14 #include <Ice/HashUtil.h>
15 #include <Ice/Object.h>
16 #include <Ice/Properties.h>
17 #include <Ice/UUID.h>
18 #include <IceUtil/StringUtil.h>
19 
20 using namespace std;
21 using namespace Ice;
22 using namespace IceBT;
23 
24 #ifndef ICE_CPP11_MAPPING
upCast(EndpointI * p)25 IceUtil::Shared* IceBT::upCast(EndpointI* p) { return p; }
26 #endif
27 
EndpointI(const InstancePtr & instance,const string & addr,const string & uuid,const string & name,Int channel,Int timeout,const string & connectionId,bool compress)28 IceBT::EndpointI::EndpointI(const InstancePtr& instance, const string& addr, const string& uuid, const string& name,
29                             Int channel, Int timeout, const string& connectionId, bool compress) :
30     _instance(instance),
31     _addr(addr),
32     _uuid(uuid),
33     _name(name),
34     _channel(channel),
35     _timeout(timeout),
36     _connectionId(connectionId),
37     _compress(compress),
38     _hashValue(0)
39 {
40     hashInit();
41 }
42 
EndpointI(const InstancePtr & instance)43 IceBT::EndpointI::EndpointI(const InstancePtr& instance) :
44     _instance(instance),
45     _channel(0),
46     _timeout(instance->defaultTimeout()),
47     _compress(false),
48     _hashValue(0)
49 {
50 }
51 
EndpointI(const InstancePtr & instance,InputStream * s)52 IceBT::EndpointI::EndpointI(const InstancePtr& instance, InputStream* s) :
53     _instance(instance),
54     _channel(0),
55     _timeout(-1),
56     _compress(false),
57     _hashValue(0)
58 {
59     //
60     // _name and _channel are not marshaled.
61     //
62     s->read(const_cast<string&>(_addr), false);
63     s->read(const_cast<string&>(_uuid), false);
64     s->read(const_cast<Int&>(_timeout));
65     s->read(const_cast<bool&>(_compress));
66     hashInit();
67 }
68 
69 void
streamWriteImpl(OutputStream * s) const70 IceBT::EndpointI::streamWriteImpl(OutputStream* s) const
71 {
72     //
73     // _name and _channel are not marshaled.
74     //
75     s->write(_addr, false);
76     s->write(_uuid, false);
77     s->write(_timeout);
78     s->write(_compress);
79 }
80 
81 Ice::Short
type() const82 IceBT::EndpointI::type() const
83 {
84     return _instance->type();
85 }
86 
87 const string&
protocol() const88 IceBT::EndpointI::protocol() const
89 {
90     return _instance->protocol();
91 }
92 
93 Int
timeout() const94 IceBT::EndpointI::timeout() const
95 {
96     return _timeout;
97 }
98 
99 IceInternal::EndpointIPtr
timeout(Int timeout) const100 IceBT::EndpointI::timeout(Int timeout) const
101 {
102     if(timeout == _timeout)
103     {
104         return ICE_SHARED_FROM_CONST_THIS(EndpointI);
105     }
106     else
107     {
108         return ICE_MAKE_SHARED(EndpointI, _instance, _addr, _uuid, _name, _channel, timeout, _connectionId, _compress);
109     }
110 }
111 
112 const string&
connectionId() const113 IceBT::EndpointI::connectionId() const
114 {
115     return _connectionId;
116 }
117 
118 IceInternal::EndpointIPtr
connectionId(const string & connectionId) const119 IceBT::EndpointI::connectionId(const string& connectionId) const
120 {
121     if(connectionId == _connectionId)
122     {
123         return ICE_SHARED_FROM_CONST_THIS(EndpointI);
124     }
125     else
126     {
127         return ICE_MAKE_SHARED(EndpointI, _instance, _addr, _uuid, _name, _channel, _timeout, connectionId, _compress);
128     }
129 }
130 
131 bool
compress() const132 IceBT::EndpointI::compress() const
133 {
134     return _compress;
135 }
136 
137 IceInternal::EndpointIPtr
compress(bool compress) const138 IceBT::EndpointI::compress(bool compress) const
139 {
140     if(compress == _compress)
141     {
142         return ICE_SHARED_FROM_CONST_THIS(EndpointI);
143     }
144     else
145     {
146         return ICE_MAKE_SHARED(EndpointI, _instance, _addr, _uuid, _name, _channel, _timeout, _connectionId, compress);
147     }
148 }
149 
150 bool
datagram() const151 IceBT::EndpointI::datagram() const
152 {
153     return false;
154 }
155 
156 bool
secure() const157 IceBT::EndpointI::secure() const
158 {
159     return _instance->secure();
160 }
161 
162 IceInternal::TransceiverPtr
transceiver() const163 IceBT::EndpointI::transceiver() const
164 {
165     return 0;
166 }
167 
168 void
connectors_async(EndpointSelectionType,const IceInternal::EndpointI_connectorsPtr & cb) const169 IceBT::EndpointI::connectors_async(EndpointSelectionType /*selType*/, const IceInternal::EndpointI_connectorsPtr& cb) const
170 {
171     vector<IceInternal::ConnectorPtr> connectors;
172     connectors.push_back(new ConnectorI(_instance, _addr, _uuid, _timeout, _connectionId));
173     cb->connectors(connectors);
174 }
175 
176 IceInternal::AcceptorPtr
acceptor(const string & adapterName) const177 IceBT::EndpointI::acceptor(const string& adapterName) const
178 {
179     return new AcceptorI(ICE_SHARED_FROM_CONST_THIS(EndpointI), _instance, adapterName, _addr, _uuid, _name, _channel);
180 }
181 
182 vector<IceInternal::EndpointIPtr>
expandIfWildcard() const183 IceBT::EndpointI::expandIfWildcard() const
184 {
185     vector<IceInternal::EndpointIPtr> endps;
186 
187     if(_addr.empty())
188     {
189         //
190         // getDefaultAdapterAddress will raise BluetoothException if no adapter is present.
191         //
192         string addr = _instance->engine()->getDefaultAdapterAddress();
193         endps.push_back(ICE_MAKE_SHARED(EndpointI, _instance, addr, _uuid, _name, _channel, _timeout, _connectionId,
194                                         _compress));
195     }
196     else
197     {
198         endps.push_back(ICE_SHARED_FROM_CONST_THIS(EndpointI));
199     }
200 
201     return endps;
202 }
203 
204 vector<IceInternal::EndpointIPtr>
expandHost(IceInternal::EndpointIPtr &) const205 IceBT::EndpointI::expandHost(IceInternal::EndpointIPtr&) const
206 {
207     //
208     // Nothing to do here.
209     //
210     vector<IceInternal::EndpointIPtr> endps;
211     endps.push_back(ICE_SHARED_FROM_CONST_THIS(EndpointI));
212     return endps;
213 }
214 
215 bool
equivalent(const IceInternal::EndpointIPtr & endpoint) const216 IceBT::EndpointI::equivalent(const IceInternal::EndpointIPtr& endpoint) const
217 {
218     const EndpointI* btEndpointI = dynamic_cast<const EndpointI*>(endpoint.get());
219     if(!btEndpointI)
220     {
221         return false;
222     }
223     return btEndpointI->type() == type() && btEndpointI->_addr == _addr && btEndpointI->_uuid == _uuid;
224 }
225 
226 bool
227 #ifdef ICE_CPP11_MAPPING
operator ==(const Ice::Endpoint & r) const228 IceBT::EndpointI::operator==(const Ice::Endpoint& r) const
229 #else
230 IceBT::EndpointI::operator==(const Ice::LocalObject& r) const
231 #endif
232 {
233     const EndpointI* p = dynamic_cast<const EndpointI*>(&r);
234     if(!p)
235     {
236         return false;
237     }
238 
239     if(this == p)
240     {
241         return true;
242     }
243 
244     if(_addr != p->_addr)
245     {
246         return false;
247     }
248 
249     if(_uuid != p->_uuid)
250     {
251         return false;
252     }
253 
254     if(_connectionId != p->_connectionId)
255     {
256         return false;
257     }
258 
259     if(_channel != p->_channel)
260     {
261         return false;
262     }
263 
264     if(_timeout != p->_timeout)
265     {
266         return false;
267     }
268 
269     if(_compress != p->_compress)
270     {
271         return false;
272     }
273 
274     return true;
275 }
276 
277 bool
278 #ifdef ICE_CPP11_MAPPING
operator <(const Ice::Endpoint & r) const279 IceBT::EndpointI::operator<(const Ice::Endpoint& r) const
280 #else
281 IceBT::EndpointI::operator<(const Ice::LocalObject& r) const
282 #endif
283 {
284     const EndpointI* p = dynamic_cast<const EndpointI*>(&r);
285     if(!p)
286     {
287         const IceInternal::EndpointI* e = dynamic_cast<const IceInternal::EndpointI*>(&r);
288         if(!e)
289         {
290             return false;
291         }
292         return type() < e->type();
293     }
294 
295     if(this == p)
296     {
297         return false;
298     }
299 
300     if(type() < p->type())
301     {
302         return true;
303     }
304     else if(p->type() < type())
305     {
306         return false;
307     }
308 
309     if(_addr < p->_addr)
310     {
311         return true;
312     }
313     else if(p->_addr < _addr)
314     {
315         return false;
316     }
317 
318     if(_uuid < p->_uuid)
319     {
320         return true;
321     }
322     else if(p->_uuid < _uuid)
323     {
324         return false;
325     }
326 
327     if(_connectionId < p->_connectionId)
328     {
329         return true;
330     }
331     else if(p->_connectionId < _connectionId)
332     {
333         return false;
334     }
335 
336     if(_channel < p->_channel)
337     {
338         return true;
339     }
340     else if(p->_channel < _channel)
341     {
342         return false;
343     }
344 
345     if(_timeout < p->_timeout)
346     {
347         return true;
348     }
349     else if(p->_timeout < _timeout)
350     {
351         return false;
352     }
353 
354     if(!_compress && p->_compress)
355     {
356         return true;
357     }
358     else if(p->_compress < _compress)
359     {
360         return false;
361     }
362 
363     return false;
364 }
365 
366 Ice::Int
hash() const367 IceBT::EndpointI::hash() const
368 {
369     return _hashValue;
370 }
371 
372 string
options() const373 IceBT::EndpointI::options() const
374 {
375     //
376     // WARNING: Certain features, such as proxy validation in Glacier2,
377     // depend on the format of proxy strings. Changes to toString() and
378     // methods called to generate parts of the reference string could break
379     // these features. Please review for all features that depend on the
380     // format of proxyToString() before changing this and related code.
381     //
382     ostringstream s;
383 
384     if(!_addr.empty())
385     {
386         s << " -a ";
387         bool addQuote = _addr.find(':') != string::npos;
388         if(addQuote)
389         {
390             s << "\"";
391         }
392         s << _addr;
393         if(addQuote)
394         {
395             s << "\"";
396         }
397     }
398 
399     if(!_uuid.empty())
400     {
401         s << " -u ";
402         bool addQuote = _uuid.find(':') != string::npos;
403         if(addQuote)
404         {
405             s << "\"";
406         }
407         s << _uuid;
408         if(addQuote)
409         {
410             s << "\"";
411         }
412     }
413 
414     if(_channel > 0)
415     {
416         s << " -c " << _channel;
417     }
418 
419     if(_timeout == -1)
420     {
421         s << " -t infinite";
422     }
423     else
424     {
425         s << " -t " << _timeout;
426     }
427 
428     if(_compress)
429     {
430         s << " -z";
431     }
432 
433     return s.str();
434 }
435 
436 Ice::EndpointInfoPtr
getInfo() const437 IceBT::EndpointI::getInfo() const ICE_NOEXCEPT
438 {
439     EndpointInfoPtr info = ICE_MAKE_SHARED(EndpointInfoI, ICE_SHARED_FROM_CONST_THIS(EndpointI));
440     info->addr = _addr;
441     info->uuid = _uuid;
442     return info;
443 }
444 
445 void
initWithOptions(vector<string> & args,bool oaEndpoint)446 IceBT::EndpointI::initWithOptions(vector<string>& args, bool oaEndpoint)
447 {
448     IceInternal::EndpointI::initWithOptions(args);
449 
450     if(_addr.empty())
451     {
452         const_cast<string&>(_addr) = _instance->defaultHost();
453     }
454     else if(_addr == "*")
455     {
456         if(oaEndpoint)
457         {
458             const_cast<string&>(_addr) = string();
459         }
460         else
461         {
462             throw EndpointParseException(__FILE__, __LINE__,
463                                          "`-a *' not valid for proxy endpoint `" + toString() + "'");
464         }
465     }
466 
467     if(_name.empty())
468     {
469         const_cast<string&>(_name) = "Ice Service";
470     }
471 
472     if(_uuid.empty())
473     {
474         if(oaEndpoint)
475         {
476             //
477             // Generate a UUID for object adapters that don't specify one.
478             //
479             const_cast<string&>(_uuid) = generateUUID();
480         }
481         else
482         {
483             throw EndpointParseException(__FILE__, __LINE__, "a UUID must be specified using the -u option");
484         }
485     }
486 
487     if(_channel < 0)
488     {
489         const_cast<Int&>(_channel) = 0;
490     }
491 
492     if(!oaEndpoint && _channel != 0)
493     {
494         throw EndpointParseException(__FILE__, __LINE__, "the -c option can only be used for object adapter endpoints");
495     }
496 
497     hashInit();
498 }
499 
500 IceBT::EndpointIPtr
endpoint(const AcceptorIPtr & acceptor) const501 IceBT::EndpointI::endpoint(const AcceptorIPtr& acceptor) const
502 {
503     return ICE_MAKE_SHARED(EndpointI, _instance, _addr, _uuid, _name, acceptor->effectiveChannel(), _timeout,
504                            _connectionId, _compress);
505 }
506 
507 void
hashInit()508 IceBT::EndpointI::hashInit()
509 {
510     Int h = 5381;
511     IceInternal::hashAdd(h, _addr);
512     IceInternal::hashAdd(h, _uuid);
513     IceInternal::hashAdd(h, _timeout);
514     IceInternal::hashAdd(h, _connectionId);
515     IceInternal::hashAdd(h, _compress);
516     const_cast<Int&>(_hashValue) = h;
517 }
518 
519 bool
checkOption(const string & option,const string & argument,const string & endpoint)520 IceBT::EndpointI::checkOption(const string& option, const string& argument, const string& endpoint)
521 {
522     string arg = IceUtilInternal::trim(argument);
523     if(option == "-a")
524     {
525         if(arg.empty())
526         {
527             throw EndpointParseException(__FILE__, __LINE__, "no argument provided for -a option in endpoint " +
528                                          endpoint);
529         }
530         if(arg != "*" && !isValidDeviceAddress(arg))
531         {
532             throw EndpointParseException(__FILE__, __LINE__, "invalid argument provided for -a option in endpoint " +
533                                          endpoint);
534         }
535         const_cast<string&>(_addr) = arg;
536     }
537     else if(option == "-u")
538     {
539         if(arg.empty())
540         {
541             throw EndpointParseException(__FILE__, __LINE__, "no argument provided for -u option in endpoint " +
542                                          endpoint);
543         }
544         const_cast<string&>(_uuid) = arg;
545     }
546     else if(option == "-c")
547     {
548         if(arg.empty())
549         {
550             throw EndpointParseException(__FILE__, __LINE__, "no argument provided for -c option in endpoint " +
551                                          endpoint);
552         }
553 
554         istringstream t(argument);
555         if(!(t >> const_cast<Int&>(_channel)) || !t.eof() || _channel < 0 || _channel > 30)
556         {
557             throw EndpointParseException(__FILE__, __LINE__, "invalid channel value `" + arg + "' in endpoint " +
558                                          endpoint);
559         }
560     }
561     else if(option == "-t")
562     {
563         if(arg.empty())
564         {
565             throw EndpointParseException(__FILE__, __LINE__, "no argument provided for -t option in endpoint " +
566                                          endpoint);
567         }
568 
569         if(arg == "infinite")
570         {
571             const_cast<Int&>(_timeout) = -1;
572         }
573         else
574         {
575             istringstream t(argument);
576             if(!(t >> const_cast<Int&>(_timeout)) || !t.eof() || _timeout < 1)
577             {
578                 throw EndpointParseException(__FILE__, __LINE__, "invalid timeout value `" + arg + "' in endpoint " +
579                                              endpoint);
580             }
581         }
582     }
583     else if(option == "-z")
584     {
585         if(!arg.empty())
586         {
587             throw EndpointParseException(__FILE__, __LINE__, "unexpected argument `" + arg +
588                                          "' provided for -z option in " + endpoint);
589         }
590         const_cast<bool&>(_compress) = true;
591     }
592     else if(option == "--name")
593     {
594         if(arg.empty())
595         {
596             throw EndpointParseException(__FILE__, __LINE__, "no argument provided for --name option in endpoint " +
597                                          endpoint);
598         }
599         const_cast<string&>(_name) = arg;
600     }
601     else
602     {
603         return false;
604     }
605     return true;
606 }
607 
EndpointInfoI(const EndpointIPtr & endpoint)608 IceBT::EndpointInfoI::EndpointInfoI(const EndpointIPtr& endpoint) : _endpoint(endpoint)
609 {
610 }
611 
~EndpointInfoI()612 IceBT::EndpointInfoI::~EndpointInfoI()
613 {
614 }
615 
616 Ice::Short
type() const617 IceBT::EndpointInfoI::type() const ICE_NOEXCEPT
618 {
619     return _endpoint->type();
620 }
621 
622 bool
datagram() const623 IceBT::EndpointInfoI::datagram() const ICE_NOEXCEPT
624 {
625     return _endpoint->datagram();
626 }
627 
628 bool
secure() const629 IceBT::EndpointInfoI::secure() const ICE_NOEXCEPT
630 {
631     return _endpoint->secure();
632 }
633 
EndpointFactoryI(const InstancePtr & instance)634 IceBT::EndpointFactoryI::EndpointFactoryI(const InstancePtr& instance) : _instance(instance)
635 {
636 }
637 
~EndpointFactoryI()638 IceBT::EndpointFactoryI::~EndpointFactoryI()
639 {
640 }
641 
642 Short
type() const643 IceBT::EndpointFactoryI::type() const
644 {
645     return _instance->type();
646 }
647 
648 string
protocol() const649 IceBT::EndpointFactoryI::protocol() const
650 {
651     return _instance->protocol();
652 }
653 
654 IceInternal::EndpointIPtr
create(vector<string> & args,bool oaEndpoint) const655 IceBT::EndpointFactoryI::create(vector<string>& args, bool oaEndpoint) const
656 {
657     EndpointIPtr endpt = ICE_MAKE_SHARED(EndpointI, _instance);
658     endpt->initWithOptions(args, oaEndpoint);
659     return endpt;
660 }
661 
662 IceInternal::EndpointIPtr
read(InputStream * s) const663 IceBT::EndpointFactoryI::read(InputStream* s) const
664 {
665     return ICE_MAKE_SHARED(EndpointI, _instance, s);
666 }
667 
668 void
destroy()669 IceBT::EndpointFactoryI::destroy()
670 {
671     _instance = 0;
672 }
673 
674 IceInternal::EndpointFactoryPtr
clone(const IceInternal::ProtocolInstancePtr & instance) const675 IceBT::EndpointFactoryI::clone(const IceInternal::ProtocolInstancePtr& instance) const
676 {
677     return new EndpointFactoryI(new Instance(_instance->engine(), instance->type(), instance->protocol()));
678 }
679