1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	/*
4    	 * Ceph - scalable distributed file system
5    	 *
6    	 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7    	 *
8    	 * This is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License version 2.1, as published by the Free Software
11   	 * Foundation.  See file COPYING.
12   	 *
13   	 */
14   	
15   	#ifndef CEPH_MSG_TYPES_H
16   	#define CEPH_MSG_TYPES_H
17   	
18   	#include <sstream>
19   	
20   	#include <netinet/in.h>
21   	
22   	#include "include/ceph_features.h"
23   	#include "include/types.h"
24   	#include "include/blobhash.h"
25   	#include "include/encoding.h"
26   	
27   	#define MAX_PORT_NUMBER 65535
28   	
29   	namespace ceph {
30   	  class Formatter;
31   	}
32   	
33   	std::ostream& operator<<(std::ostream& out, const sockaddr_storage &ss);
34   	std::ostream& operator<<(std::ostream& out, const sockaddr *sa);
35   	
36   	typedef uint8_t entity_type_t;
37   	
38   	class entity_name_t {
39   	public:
40   	  entity_type_t _type;
41   	  int64_t _num;
42   	
43   	public:
44   	  static const int TYPE_MON = CEPH_ENTITY_TYPE_MON;
45   	  static const int TYPE_MDS = CEPH_ENTITY_TYPE_MDS;
46   	  static const int TYPE_OSD = CEPH_ENTITY_TYPE_OSD;
47   	  static const int TYPE_CLIENT = CEPH_ENTITY_TYPE_CLIENT;
48   	  static const int TYPE_MGR = CEPH_ENTITY_TYPE_MGR;
49   	
50   	  static const int64_t NEW = -1;
51   	
52   	  // cons
53   	  entity_name_t() : _type(0), _num(0) { }
54   	  entity_name_t(int t, int64_t n) : _type(t), _num(n) { }
55   	  explicit entity_name_t(const ceph_entity_name &n) :
56   	    _type(n.type), _num(n.num) { }
57   	
58   	  // static cons
59   	  static entity_name_t MON(int64_t i=NEW) { return entity_name_t(TYPE_MON, i); }
60   	  static entity_name_t MDS(int64_t i=NEW) { return entity_name_t(TYPE_MDS, i); }
61   	  static entity_name_t OSD(int64_t i=NEW) { return entity_name_t(TYPE_OSD, i); }
62   	  static entity_name_t CLIENT(int64_t i=NEW) { return entity_name_t(TYPE_CLIENT, i); }
63   	  static entity_name_t MGR(int64_t i=NEW) { return entity_name_t(TYPE_MGR, i); }
64   	
65   	  int64_t num() const { return _num; }
66   	  int type() const { return _type; }
67   	  const char *type_str() const {
68   	    return ceph_entity_type_name(type());
69   	  }
70   	
71   	  bool is_new() const { return num() < 0; }
72   	
73   	  bool is_client() const { return type() == TYPE_CLIENT; }
74   	  bool is_mds() const { return type() == TYPE_MDS; }
75   	  bool is_osd() const { return type() == TYPE_OSD; }
76   	  bool is_mon() const { return type() == TYPE_MON; }
77   	  bool is_mgr() const { return type() == TYPE_MGR; }
78   	
79   	  operator ceph_entity_name() const {
80   	    ceph_entity_name n = { _type, init_le64(_num) };
81   	    return n;
82   	  }
83   	
84   	  bool parse(const std::string& s) {
85   	    const char *start = s.c_str();
86   	    char *end;
87   	    bool got = parse(start, &end);
88   	    return got && end == start + s.length();
89   	  }
90   	  bool parse(const char *start, char **end) {
91   	    if (strstr(start, "mon.") == start) {
92   	      _type = TYPE_MON;
93   	      start += 4;
94   	    } else if (strstr(start, "osd.") == start) {
95   	      _type = TYPE_OSD;
96   	      start += 4;
97   	    } else if (strstr(start, "mds.") == start) {
98   	      _type = TYPE_MDS;
99   	      start += 4;
100  	    } else if (strstr(start, "client.") == start) {
101  	      _type = TYPE_CLIENT;
102  	      start += 7;
103  	    } else if (strstr(start, "mgr.") == start) {
104  	      _type = TYPE_MGR;
105  	      start += 4;
106  	    } else {
107  	      return false;
108  	    }
109  	    if (isspace(*start))
110  	      return false;
111  	    _num = strtoll(start, end, 10);
112  	    if (*end == NULL || *end == start)
113  	      return false;
114  	    return true;
115  	  }
116  	
117  	  DENC(entity_name_t, v, p) {
118  	    denc(v._type, p);
119  	    denc(v._num, p);
120  	  }
121  	  void dump(ceph::Formatter *f) const;
122  	
123  	  static void generate_test_instances(std::list<entity_name_t*>& o);
124  	};
125  	WRITE_CLASS_DENC(entity_name_t)
126  	
127  	inline bool operator== (const entity_name_t& l, const entity_name_t& r) {
128  	  return (l.type() == r.type()) && (l.num() == r.num()); }
129  	inline bool operator!= (const entity_name_t& l, const entity_name_t& r) {
130  	  return (l.type() != r.type()) || (l.num() != r.num()); }
131  	inline bool operator< (const entity_name_t& l, const entity_name_t& r) {
132  	  return (l.type() < r.type()) || (l.type() == r.type() && l.num() < r.num()); }
133  	
134  	inline std::ostream& operator<<(std::ostream& out, const entity_name_t& addr) {
135  	  //if (addr.is_namer()) return out << "namer";
136  	  if (addr.is_new() || addr.num() < 0)
137  	    return out << addr.type_str() << ".?";
138  	  else
139  	    return out << addr.type_str() << '.' << addr.num();
140  	}
141  	inline std::ostream& operator<<(std::ostream& out, const ceph_entity_name& addr) {
142  	  return out << entity_name_t{addr.type, static_cast<int64_t>(addr.num)};
143  	}
144  	
145  	namespace std {
146  	  template<> struct hash< entity_name_t >
147  	  {
148  	    size_t operator()( const entity_name_t &m ) const
149  	    {
150  	      return rjhash32(m.type() ^ m.num());
151  	    }
152  	  };
153  	} // namespace std
154  	
155  	// define a wire format for sockaddr that matches Linux's.
156  	struct ceph_sockaddr_storage {
157  	  ceph_le16 ss_family;
158  	  __u8 __ss_padding[128 - sizeof(ceph_le16)];
159  	
160  	  void encode(ceph::buffer::list& bl) const {
161  	    struct ceph_sockaddr_storage ss = *this;
162  	    ss.ss_family = htons(ss.ss_family);
163  	    ceph::encode_raw(ss, bl);
164  	  }
165  	
166  	  void decode(ceph::buffer::list::const_iterator& bl) {
167  	    struct ceph_sockaddr_storage ss;
168  	    ceph::decode_raw(ss, bl);
169  	    ss.ss_family = ntohs(ss.ss_family);
170  	    *this = ss;
171  	  }
172  	} __attribute__ ((__packed__));
173  	WRITE_CLASS_ENCODER(ceph_sockaddr_storage)
174  	
175  	/*
176  	 * encode sockaddr.ss_family as network byte order
177  	 */
178  	static inline void encode(const sockaddr_storage& a, ceph::buffer::list& bl) {
179  	#if defined(__linux__)
180  	  struct sockaddr_storage ss = a;
181  	  ss.ss_family = htons(ss.ss_family);
182  	  ceph::encode_raw(ss, bl);
183  	#elif defined(__FreeBSD__) || defined(__APPLE__)
184  	  ceph_sockaddr_storage ss{};
185  	  auto src = (unsigned char const *)&a;
186  	  auto dst = (unsigned char *)&ss;
187  	  src += sizeof(a.ss_len);
188  	  ss.ss_family = a.ss_family;
189  	  src += sizeof(a.ss_family);
190  	  dst += sizeof(ss.ss_family);
191  	  const auto copy_size = std::min((unsigned char*)(&a + 1) - src,
192  					  (unsigned char*)(&ss + 1) - dst);
193  	  ::memcpy(dst, src, copy_size);
194  	  encode(ss, bl);
195  	#else
196  	  ceph_sockaddr_storage ss{};
197  	  ::memset(&ss, '\0', sizeof(ss));
198  	  ::memcpy(&wireaddr, &ss, std::min(sizeof(ss), sizeof(a)));
199  	  encode(ss, bl);
200  	#endif
201  	}
202  	static inline void decode(sockaddr_storage& a,
203  				  ceph::buffer::list::const_iterator& bl) {
204  	#if defined(__linux__)
205  	  ceph::decode_raw(a, bl);
206  	  a.ss_family = ntohs(a.ss_family);
207  	#elif defined(__FreeBSD__) || defined(__APPLE__)
208  	  ceph_sockaddr_storage ss{};
209  	  decode(ss, bl);
210  	  auto src = (unsigned char const *)&ss;
211  	  auto dst = (unsigned char *)&a;
212  	  a.ss_len = 0;
213  	  dst += sizeof(a.ss_len);
214  	  a.ss_family = ss.ss_family;
215  	  src += sizeof(ss.ss_family);
216  	  dst += sizeof(a.ss_family);
217  	  auto const copy_size = std::min((unsigned char*)(&ss + 1) - src,
218  					  (unsigned char*)(&a + 1) - dst);
219  	  ::memcpy(dst, src, copy_size);
220  	#else
221  	  ceph_sockaddr_storage ss{};
222  	  decode(ss, bl);
223  	  ::memcpy(&a, &ss, std::min(sizeof(ss), sizeof(a)));
224  	#endif
225  	}
226  	
227  	/*
228  	 * an entity's network address.
229  	 * includes a random value that prevents it from being reused.
230  	 * thus identifies a particular process instance.
231  	 * ipv4 for now.
232  	 */
233  	struct entity_addr_t {
234  	  typedef enum {
235  	    TYPE_NONE = 0,
236  	    TYPE_LEGACY = 1,  ///< legacy msgr1 protocol (ceph jewel and older)
237  	    TYPE_MSGR2 = 2,   ///< msgr2 protocol (new in ceph kraken)
238  	    TYPE_ANY = 3,  ///< ambiguous
239  	  } type_t;
240  	  static const type_t TYPE_DEFAULT = TYPE_MSGR2;
241  	  static std::string_view get_type_name(int t) {
242  	    switch (t) {
243  	    case TYPE_NONE: return "none";
244  	    case TYPE_LEGACY: return "v1";
245  	    case TYPE_MSGR2: return "v2";
246  	    case TYPE_ANY: return "any";
247  	    default: return "???";
248  	    }
249  	  };
250  	
251  	  __u32 type;
252  	  __u32 nonce;
253  	  union {
254  	    sockaddr sa;
255  	    sockaddr_in sin;
256  	    sockaddr_in6 sin6;
257  	  } u;
258  	
259  	  entity_addr_t() : type(0), nonce(0) {
260  	    memset(&u, 0, sizeof(u));
261  	  }
262  	  entity_addr_t(__u32 _type, __u32 _nonce) : type(_type), nonce(_nonce) {
263  	    memset(&u, 0, sizeof(u));
264  	  }
265  	  explicit entity_addr_t(const ceph_entity_addr &o) {
266  	    type = o.type;
267  	    nonce = o.nonce;
268  	    memcpy(&u, &o.in_addr, sizeof(u));
269  	#if !defined(__FreeBSD__)
270  	    u.sa.sa_family = ntohs(u.sa.sa_family);
271  	#endif
272  	  }
273  	
274  	  uint32_t get_type() const { return type; }
275  	  void set_type(uint32_t t) { type = t; }
276  	  bool is_legacy() const { return type == TYPE_LEGACY; }
277  	  bool is_msgr2() const { return type == TYPE_MSGR2; }
278  	  bool is_any() const { return type == TYPE_ANY; }
279  	
280  	  __u32 get_nonce() const { return nonce; }
281  	  void set_nonce(__u32 n) { nonce = n; }
282  	
283  	  int get_family() const {
284  	    return u.sa.sa_family;
285  	  }
286  	  void set_family(int f) {
287  	    u.sa.sa_family = f;
288  	  }
289  	
290  	  bool is_ipv4() const {
291  	    return u.sa.sa_family == AF_INET;
292  	  }
293  	  bool is_ipv6() const {
294  	    return u.sa.sa_family == AF_INET6;
295  	  }
296  	
297  	  sockaddr_in &in4_addr() {
298  	    return u.sin;
299  	  }
300  	  const sockaddr_in &in4_addr() const{
301  	    return u.sin;
302  	  }
303  	  sockaddr_in6 &in6_addr(){
304  	    return u.sin6;
305  	  }
306  	  const sockaddr_in6 &in6_addr() const{
307  	    return u.sin6;
308  	  }
309  	  const sockaddr *get_sockaddr() const {
310  	    return &u.sa;
311  	  }
312  	  size_t get_sockaddr_len() const {
313  	    switch (u.sa.sa_family) {
314  	    case AF_INET:
315  	      return sizeof(u.sin);
316  	    case AF_INET6:
317  	      return sizeof(u.sin6);
318  	    }
319  	    return sizeof(u);
320  	  }
321  	  bool set_sockaddr(const struct sockaddr *sa)
322  	  {
323  	    switch (sa->sa_family) {
324  	    case AF_INET:
325  	      // pre-zero, since we're only copying a portion of the source
326  	      memset(&u, 0, sizeof(u));
327  	      memcpy(&u.sin, sa, sizeof(u.sin));
328  	      break;
329  	    case AF_INET6:
330  	      // pre-zero, since we're only copying a portion of the source
331  	      memset(&u, 0, sizeof(u));
332  	      memcpy(&u.sin6, sa, sizeof(u.sin6));
333  	      break;
334  	    case AF_UNSPEC:
335  	      memset(&u, 0, sizeof(u));
336  	      break;
337  	    default:
338  	      return false;
339  	    }
340  	    return true;
341  	  }
342  	
343  	  sockaddr_storage get_sockaddr_storage() const {
344  	    sockaddr_storage ss;
345  	    memcpy(&ss, &u, sizeof(u));
346  	    memset((char*)&ss + sizeof(u), 0, sizeof(ss) - sizeof(u));
347  	    return ss;
348  	  }
349  	
350  	  void set_in4_quad(int pos, int val) {
351  	    u.sin.sin_family = AF_INET;
352  	    unsigned char *ipq = (unsigned char*)&u.sin.sin_addr.s_addr;
353  	    ipq[pos] = val;
354  	  }
355  	  void set_port(int port) {
356  	    switch (u.sa.sa_family) {
357  	    case AF_INET:
358  	      u.sin.sin_port = htons(port);
359  	      break;
360  	    case AF_INET6:
361  	      u.sin6.sin6_port = htons(port);
362  	      break;
363  	    default:
364  	      ceph_abort();
365  	    }
366  	  }
367  	  int get_port() const {
368  	    switch (u.sa.sa_family) {
369  	    case AF_INET:
370  	      return ntohs(u.sin.sin_port);
371  	      break;
372  	    case AF_INET6:
373  	      return ntohs(u.sin6.sin6_port);
374  	      break;
375  	    }
376  	    return 0;
377  	  }
378  	
379  	  operator ceph_entity_addr() const {
380  	    ceph_entity_addr a;
381  	    a.type = 0;
382  	    a.nonce = nonce;
383  	    a.in_addr = get_sockaddr_storage();
384  	#if !defined(__FreeBSD__)
385  	    a.in_addr.ss_family = htons(a.in_addr.ss_family);
386  	#endif
387  	    return a;
388  	  }
389  	
390  	  bool probably_equals(const entity_addr_t &o) const {
391  	    if (get_port() != o.get_port())
392  	      return false;
393  	    if (get_nonce() != o.get_nonce())
394  	      return false;
395  	    if (is_blank_ip() || o.is_blank_ip())
396  	      return true;
397  	    if (memcmp(&u, &o.u, sizeof(u)) == 0)
398  	      return true;
399  	    return false;
400  	  }
401  	
402  	  bool is_same_host(const entity_addr_t &o) const {
403  	    if (u.sa.sa_family != o.u.sa.sa_family)
404  	      return false;
405  	    if (u.sa.sa_family == AF_INET)
406  	      return u.sin.sin_addr.s_addr == o.u.sin.sin_addr.s_addr;
407  	    if (u.sa.sa_family == AF_INET6)
408  	      return memcmp(u.sin6.sin6_addr.s6_addr,
409  			    o.u.sin6.sin6_addr.s6_addr,
410  			    sizeof(u.sin6.sin6_addr.s6_addr)) == 0;
411  	    return false;
412  	  }
413  	
414  	  bool is_blank_ip() const {
415  	    switch (u.sa.sa_family) {
416  	    case AF_INET:
417  	      return u.sin.sin_addr.s_addr == INADDR_ANY;
418  	    case AF_INET6:
419  	      return memcmp(&u.sin6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0;
420  	    default:
421  	      return true;
422  	    }
423  	  }
424  	
425  	  bool is_ip() const {
426  	    switch (u.sa.sa_family) {
427  	    case AF_INET:
428  	    case AF_INET6:
429  	      return true;
430  	    default:
431  	      return false;
432  	    }
433  	  }
434  	
435  	  std::string ip_only_to_str() const;
436  	
437  	  std::string get_legacy_str() const {
438  	    std::ostringstream ss;
439  	    ss << get_sockaddr() << "/" << get_nonce();
440  	    return ss.str();
441  	  }
442  	
443  	  bool parse(const char *s, const char **end = 0, int type=0);
444  	
445  	  void decode_legacy_addr_after_marker(ceph::buffer::list::const_iterator& bl)
446  	  {
447  	    using ceph::decode;
448  	    __u8 marker;
449  	    __u16 rest;
450  	    decode(marker, bl);
451  	    decode(rest, bl);
452  	    decode(nonce, bl);
453  	    sockaddr_storage ss;
454  	    decode(ss, bl);
455  	    set_sockaddr((sockaddr*)&ss);
456  	    if (get_family() == AF_UNSPEC) {
457  	      type = TYPE_NONE;
458  	    } else {
459  	      type = TYPE_LEGACY;
460  	    }
461  	  }
462  	
463  	  // Right now, these only deal with sockaddr_storage that have only family and content.
464  	  // Apparently on BSD there is also an ss_len that we need to handle; this requires
465  	  // broader study
466  	
467  	  void encode(ceph::buffer::list& bl, uint64_t features) const {
468  	    using ceph::encode;
(1) Event cond_false: Condition "(features & 576460752303423488UL /* CEPH_FEATURE_MSG_ADDR2 */) == 0", taking false branch.
469  	    if ((features & CEPH_FEATURE_MSG_ADDR2) == 0) {
470  	      encode((__u32)0, bl);
471  	      encode(nonce, bl);
472  	      sockaddr_storage ss = get_sockaddr_storage();
473  	      encode(ss, bl);
474  	      return;
(2) Event if_end: End of if statement.
475  	    }
(3) Event overrun-buffer-val: Overrunning buffer pointed to by "__u8 const(1)" of 1 bytes by passing it to a function which accesses it at byte offset 7. [details]
476  	    encode((__u8)1, bl);
477  	    ENCODE_START(1, 1, bl);
478  	    if (HAVE_FEATURE(features, SERVER_NAUTILUS)) {
479  	      encode(type, bl);
480  	    } else {
481  	      // map any -> legacy for old clients.  this is primary for the benefit
482  	      // of OSDMap's blacklist, but is reasonable in general since any: is
483  	      // meaningless for pre-nautilus clients or daemons.
484  	      auto t = type;
485  	      if (t == TYPE_ANY) {
486  		t = TYPE_LEGACY;
487  	      }
488  	      encode(t, bl);
489  	    }
490  	    encode(nonce, bl);
491  	    __u32 elen = get_sockaddr_len();
492  	#if (__FreeBSD__) || defined(__APPLE__)
493  	      elen -= sizeof(u.sa.sa_len);
494  	#endif
495  	    encode(elen, bl);
496  	    if (elen) {
497  	      uint16_t ss_family = u.sa.sa_family;
498  	
499  	      encode(ss_family, bl);
500  	      elen -= sizeof(u.sa.sa_family);
501  	      bl.append(u.sa.sa_data, elen);
502  	    }
503  	    ENCODE_FINISH(bl);
504  	  }
505  	  void decode(ceph::buffer::list::const_iterator& bl) {
506  	    using ceph::decode;
507  	    __u8 marker;
508  	    decode(marker, bl);
509  	    if (marker == 0) {
510  	      decode_legacy_addr_after_marker(bl);
511  	      return;
512  	    }
513  	    if (marker != 1)
514  	      throw ceph::buffer::malformed_input("entity_addr_t marker != 1");
515  	    DECODE_START(1, bl);
516  	    decode(type, bl);
517  	    decode(nonce, bl);
518  	    __u32 elen;
519  	    decode(elen, bl);
520  	    if (elen) {
521  	#if defined(__FreeBSD__) || defined(__APPLE__)
522  	      u.sa.sa_len = 0;
523  	#endif
524  	      uint16_t ss_family;
525  	      if (elen < sizeof(ss_family)) {
526  		throw buffer::malformed_input("elen smaller than family len");
527  	      }
528  	      decode(ss_family, bl);
529  	      u.sa.sa_family = ss_family;
530  	      elen -= sizeof(ss_family);
531  	      if (elen > get_sockaddr_len() - sizeof(u.sa.sa_family)) {
532  		throw buffer::malformed_input("elen exceeds sockaddr len");
533  	      }
534  	      bl.copy(elen, u.sa.sa_data);
535  	    }
536  	    DECODE_FINISH(bl);
537  	  }
538  	
539  	  void dump(ceph::Formatter *f) const;
540  	
541  	  static void generate_test_instances(std::list<entity_addr_t*>& o);
542  	};
543  	WRITE_CLASS_ENCODER_FEATURES(entity_addr_t)
544  	
545  	std::ostream& operator<<(std::ostream& out, const entity_addr_t &addr);
546  	
547  	inline bool operator==(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) == 0; }
548  	inline bool operator!=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) != 0; }
549  	inline bool operator<(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) < 0; }
550  	inline bool operator<=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) <= 0; }
551  	inline bool operator>(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) > 0; }
552  	inline bool operator>=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) >= 0; }
553  	
554  	namespace std {
555  	template<> struct hash<entity_addr_t> {
556  	  size_t operator()( const entity_addr_t& x ) const {
557  	    static blobhash H;
558  	    return H(&x, sizeof(x));
559  	  }
560  	};
561  	} // namespace std
562  	
563  	struct entity_addrvec_t {
564  	  std::vector<entity_addr_t> v;
565  	
566  	  entity_addrvec_t() {}
567  	  explicit entity_addrvec_t(const entity_addr_t& a) : v({ a }) {}
568  	
569  	  unsigned size() const { return v.size(); }
570  	  bool empty() const { return v.empty(); }
571  	
572  	  entity_addr_t legacy_addr() const {
573  	    for (auto& a : v) {
574  	      if (a.type == entity_addr_t::TYPE_LEGACY) {
575  		return a;
576  	      }
577  	    }
578  	    return entity_addr_t();
579  	  }
580  	  entity_addr_t as_legacy_addr() const {
581  	    for (auto& a : v) {
582  	      if (a.is_legacy()) {
583  		return a;
584  	      }
585  	      if (a.is_any()) {
586  		auto b = a;
587  		b.set_type(entity_addr_t::TYPE_LEGACY);
588  		return b;
589  	      }
590  	    }
591  	    // hrm... lie!
592  	    auto a = front();
593  	    a.set_type(entity_addr_t::TYPE_LEGACY);
594  	    return a;
595  	  }
596  	  entity_addr_t front() const {
597  	    if (!v.empty()) {
598  	      return v.front();
599  	    }
600  	    return entity_addr_t();
601  	  }
602  	  entity_addr_t legacy_or_front_addr() const {
603  	    for (auto& a : v) {
604  	      if (a.type == entity_addr_t::TYPE_LEGACY) {
605  		return a;
606  	      }
607  	    }
608  	    if (!v.empty()) {
609  	      return v.front();
610  	    }
611  	    return entity_addr_t();
612  	  }
613  	  std::string get_legacy_str() const {
614  	    return legacy_or_front_addr().get_legacy_str();
615  	  }
616  	
617  	  entity_addr_t msgr2_addr() const {
618  	    for (auto &a : v) {
619  	      if (a.type == entity_addr_t::TYPE_MSGR2) {
620  	        return a;
621  	      }
622  	    }
623  	    return entity_addr_t();
624  	  }
625  	  bool has_msgr2() const {
626  	    for (auto& a : v) {
627  	      if (a.is_msgr2()) {
628  		return true;
629  	      }
630  	    }
631  	    return false;
632  	  }
633  	
634  	  bool parse(const char *s, const char **end = 0);
635  	
636  	  void get_ports(std::set<int> *ports) const {
637  	    for (auto& a : v) {
638  	      ports->insert(a.get_port());
639  	    }
640  	  }
641  	  std::set<int> get_ports() const {
642  	    std::set<int> r;
643  	    get_ports(&r);
644  	    return r;
645  	  }
646  	
647  	  void encode(ceph::buffer::list& bl, uint64_t features) const;
648  	  void decode(ceph::buffer::list::const_iterator& bl);
649  	  void dump(ceph::Formatter *f) const;
650  	  static void generate_test_instances(std::list<entity_addrvec_t*>& ls);
651  	
652  	  bool legacy_equals(const entity_addrvec_t& o) const {
653  	    if (v == o.v) {
654  	      return true;
655  	    }
656  	    if (v.size() == 1 &&
657  		front().is_legacy() &&
658  		front() == o.legacy_addr()) {
659  	      return true;
660  	    }
661  	    if (o.v.size() == 1 &&
662  		o.front().is_legacy() &&
663  		o.front() == legacy_addr()) {
664  	      return true;
665  	    }
666  	    return false;
667  	  }
668  	
669  	  bool probably_equals(const entity_addrvec_t& o) const {
670  	    for (unsigned i = 0; i < v.size(); ++i) {
671  	      if (!v[i].probably_equals(o.v[i])) {
672  		return false;
673  	      }
674  	    }
675  	    return true;
676  	  }
677  	  bool contains(const entity_addr_t& a) const {
678  	    for (auto& i : v) {
679  	      if (a == i) {
680  		return true;
681  	      }
682  	    }
683  	    return false;
684  	  }
685  	  bool is_same_host(const entity_addr_t& a) const {
686  	    for (auto& i : v) {
687  	      if (i.is_same_host(a)) {
688  		return true;
689  	      }
690  	    }
691  	    return false;
692  	  }
693  	
694  	  friend std::ostream& operator<<(std::ostream& out, const entity_addrvec_t& av) {
695  	    if (av.v.empty()) {
696  	      return out;
697  	    } else if (av.v.size() == 1) {
698  	      return out << av.v[0];
699  	    } else {
700  	      return out << av.v;
701  	    }
702  	  }
703  	
704  	  friend bool operator==(const entity_addrvec_t& l, const entity_addrvec_t& r) {
705  	    return l.v == r.v;
706  	  }
707  	  friend bool operator!=(const entity_addrvec_t& l, const entity_addrvec_t& r) {
708  	    return l.v != r.v;
709  	  }
710  	  friend bool operator<(const entity_addrvec_t& l, const entity_addrvec_t& r) {
711  	    return l.v < r.v;  // see lexicographical_compare()
712  	  }
713  	};
714  	WRITE_CLASS_ENCODER_FEATURES(entity_addrvec_t);
715  	
716  	namespace std {
717  	template<> struct hash<entity_addrvec_t> {
718  	  size_t operator()( const entity_addrvec_t& x) const {
719  	    static blobhash H;
720  	    size_t r = 0;
721  	    for (auto& i : x.v) {
722  	      r += H((const char*)&i, sizeof(i));
723  	    }
724  	    return r;
725  	  }
726  	};
727  	} // namespace std
728  	
729  	/*
730  	 * a particular entity instance
731  	 */
732  	struct entity_inst_t {
733  	  entity_name_t name;
734  	  entity_addr_t addr;
735  	  entity_inst_t() {}
736  	  entity_inst_t(entity_name_t n, const entity_addr_t& a) : name(n), addr(a) {}
737  	  // cppcheck-suppress noExplicitConstructor
738  	  entity_inst_t(const ceph_entity_inst& i) : name(i.name), addr(i.addr) { }
739  	  entity_inst_t(const ceph_entity_name& n, const ceph_entity_addr &a) : name(n), addr(a) {}
740  	  operator ceph_entity_inst() {
741  	    ceph_entity_inst i = {name, addr};
742  	    return i;
743  	  }
744  	
745  	  void encode(ceph::buffer::list& bl, uint64_t features) const {
746  	    using ceph::encode;
747  	    encode(name, bl);
748  	    encode(addr, bl, features);
749  	  }
750  	  void decode(ceph::buffer::list::const_iterator& bl) {
751  	    using ceph::decode;
752  	    decode(name, bl);
753  	    decode(addr, bl);
754  	  }
755  	
756  	  void dump(ceph::Formatter *f) const;
757  	  static void generate_test_instances(std::list<entity_inst_t*>& o);
758  	};
759  	WRITE_CLASS_ENCODER_FEATURES(entity_inst_t)
760  	
761  	
762  	inline bool operator==(const entity_inst_t& a, const entity_inst_t& b) {
763  	  return a.name == b.name && a.addr == b.addr;
764  	}
765  	inline bool operator!=(const entity_inst_t& a, const entity_inst_t& b) {
766  	  return a.name != b.name || a.addr != b.addr;
767  	}
768  	inline bool operator<(const entity_inst_t& a, const entity_inst_t& b) {
769  	  return a.name < b.name || (a.name == b.name && a.addr < b.addr);
770  	}
771  	inline bool operator<=(const entity_inst_t& a, const entity_inst_t& b) {
772  	  return a.name < b.name || (a.name == b.name && a.addr <= b.addr);
773  	}
774  	inline bool operator>(const entity_inst_t& a, const entity_inst_t& b) { return b < a; }
775  	inline bool operator>=(const entity_inst_t& a, const entity_inst_t& b) { return b <= a; }
776  	
777  	namespace std {
778  	  template<> struct hash< entity_inst_t >
779  	  {
780  	    size_t operator()( const entity_inst_t& x ) const
781  	    {
782  	      static hash< entity_name_t > H;
783  	      static hash< entity_addr_t > I;
784  	      return H(x.name) ^ I(x.addr);
785  	    }
786  	  };
787  	} // namespace std
788  	
789  	
790  	inline std::ostream& operator<<(std::ostream& out, const entity_inst_t &i)
791  	{
792  	  return out << i.name << " " << i.addr;
793  	}
794  	inline std::ostream& operator<<(std::ostream& out, const ceph_entity_inst &i)
795  	{
796  	  entity_inst_t n = i;
797  	  return out << n;
798  	}
799  	
800  	#endif
801