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_MON_SESSION_H
16   	#define CEPH_MON_SESSION_H
17   	
18   	#include <string>
19   	#include <string_view>
20   	
21   	#include "include/utime.h"
22   	#include "include/xlist.h"
23   	
24   	#include "global/global_context.h"
25   	#include "msg/msg_types.h"
26   	#include "mon/mon_types.h"
27   	
28   	#include "auth/AuthServiceHandler.h"
29   	#include "osd/OSDMap.h"
30   	
31   	#include "MonCap.h"
32   	
33   	struct MonSession;
34   	
35   	struct Subscription {
36   	  MonSession *session;
37   	  std::string type;
38   	  xlist<Subscription*>::item type_item;
39   	  version_t next;
40   	  bool onetime;
41   	  bool incremental_onetime;  // has CEPH_FEATURE_INCSUBOSDMAP
42   	  
43   	  Subscription(MonSession *s, const std::string& t) : session(s), type(t), type_item(this),
44   							 next(0), onetime(false), incremental_onetime(false) {}
45   	};
46   	
47   	struct MonSession : public RefCountedObject {
48   	  ConnectionRef con;
49   	  int con_type = 0;
50   	  uint64_t con_features = 0;  // zero if AnonConnection
51   	  entity_name_t name;
52   	  entity_addrvec_t addrs;
53   	  entity_addr_t socket_addr;
54   	  utime_t session_timeout;
55   	  bool closed = false;
56   	  xlist<MonSession*>::item item;
57   	  std::set<uint64_t> routed_request_tids;
58   	  MonCap caps;
59   	
60   	  bool authenticated = false;  ///< true if auth handshake is complete
61   	
62   	  std::map<std::string, Subscription*> sub_map;
63   	  epoch_t osd_epoch = 0;       ///< the osdmap epoch sent to the mon client
64   	
65   	  AuthServiceHandler *auth_handler = nullptr;
66   	  EntityName entity_name;
67   	
68   	  ConnectionRef proxy_con;
69   	  uint64_t proxy_tid = 0;
70   	
71   	  std::string remote_host;                ///< remote host name
72   	  std::map<std::string,std::string,std::less<>> last_config;    ///< most recently shared config
73   	  bool any_config = false;
74   	
75   	  MonSession(Connection *c)
76   	    : RefCountedObject(g_ceph_context),
77   	      con(c),
78   	      item(this) { }
79   	
80   	  void _ident(const entity_name_t& n, const entity_addrvec_t& av) {
81   	    con_type = con->get_peer_type();
82   	    name = n;
83   	    addrs = av;
84   	    socket_addr = con->get_peer_socket_addr();
85   	    if (con->get_messenger()) {
86   	      // only fill in features if this is a non-anonymous connection
87   	      con_features = con->get_features();
88   	    }
89   	  }
90   	
(1) Event exn_spec_violation: An exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE" is thrown but the throw list "throw()" doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate().
Also see events: [fun_call_w_exception]
91   	  ~MonSession() override {
92   	    //generic_dout(0) << "~MonSession " << this << dendl;
93   	    // we should have been removed before we get destructed; see MonSessionMap::remove_session()
94   	    ceph_assert(!item.is_on_list());
(2) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
Also see events: [exn_spec_violation]
95   	    ceph_assert(sub_map.empty());
96   	    delete auth_handler;
97   	  }
98   	
99   	  bool is_capable(std::string service, int mask) {
100  	    std::map<std::string,std::string> args;
101  	    return caps.is_capable(
102  	      g_ceph_context,
103  	      CEPH_ENTITY_TYPE_MON,
104  	      entity_name,
105  	      service, "", args,
106  	      mask & MON_CAP_R, mask & MON_CAP_W, mask & MON_CAP_X,
107  	      get_peer_socket_addr());
108  	  }
109  	
110  	  const entity_addr_t& get_peer_socket_addr() {
111  	    return socket_addr;
112  	  }
113  	};
114  	
115  	
116  	struct MonSessionMap {
117  	  xlist<MonSession*> sessions;
118  	  std::map<std::string, xlist<Subscription*>* > subs;
119  	  std::multimap<int, MonSession*> by_osd;
120  	  FeatureMap feature_map; // type -> features -> count
121  	
122  	  MonSessionMap() {}
123  	  ~MonSessionMap() {
124  	    while (!subs.empty()) {
125  	      ceph_assert(subs.begin()->second->empty());
126  	      delete subs.begin()->second;
127  	      subs.erase(subs.begin());
128  	    }
129  	  }
130  	
131  	  unsigned get_size() const {
132  	    return sessions.size();
133  	  }
134  	
135  	  void remove_session(MonSession *s) {
136  	    ceph_assert(!s->closed);
137  	    for (std::map<std::string,Subscription*>::iterator p = s->sub_map.begin(); p != s->sub_map.end(); ++p) {
138  	      p->second->type_item.remove_myself();
139  	      delete p->second;
140  	    }
141  	    s->sub_map.clear();
142  	    s->item.remove_myself();
143  	    if (s->name.is_osd()) {
144  	      for (auto p = by_osd.find(s->name.num());
145  		   p->first == s->name.num();
146  		   ++p)
147  		if (p->second == s) {
148  		  by_osd.erase(p);
149  		  break;
150  		}
151  	    }
152  	    if (s->con_features) {
153  	      feature_map.rm(s->con_type, s->con_features);
154  	    }
155  	    s->closed = true;
156  	    s->put();
157  	  }
158  	
159  	  MonSession *new_session(const entity_name_t& n,
160  				  const entity_addrvec_t& av,
161  				  Connection *c) {
162  	    MonSession *s = new MonSession(c);
163  	    ceph_assert(s);
164  	    s->_ident(n, av);
165  	    add_session(s);
166  	    return s;
167  	  }
168  	
169  	  void add_session(MonSession *s) {
170  	    sessions.push_back(&s->item);
171  	    s->get();
172  	    if (s->name.is_osd()) {
173  	      by_osd.insert(std::pair<int,MonSession*>(s->name.num(), s));
174  	    }
175  	    if (s->con_features) {
176  	      feature_map.add(s->con_type, s->con_features);
177  	    }
178  	  }
179  	
180  	  MonSession *get_random_osd_session(OSDMap *osdmap) {
181  	    // ok, this isn't actually random, but close enough.
182  	    if (by_osd.empty())
183  	      return 0;
184  	    int n = by_osd.rbegin()->first + 1;
185  	    int r = rand() % n;
186  	
187  	    auto p = by_osd.lower_bound(r);
188  	    if (p == by_osd.end())
189  	      --p;
190  	
191  	    if (!osdmap) {
192  	      return p->second;
193  	    }
194  	
195  	    MonSession *s = NULL;
196  	
197  	    auto b = p;
198  	    auto f = p;
199  	    bool backward = true, forward = true;
200  	    while (backward || forward) {
201  	      if (backward) {
202  	        if (osdmap->is_up(b->first) &&
203  		    osdmap->get_addrs(b->first) == b->second->con->get_peer_addrs()) {
204  	          s = b->second;
205  	          break;
206  	        }
207  	        if (b != by_osd.begin())
208  	          --b;
209  	        else
210  	          backward = false;
211  	      }
212  	
213  	      forward = (f != by_osd.end());
214  	      if (forward) {
215  	        if (osdmap->is_up(f->first)) {
216  	          s = f->second;
217  	          break;
218  	        }
219  	        ++f;
220  	      }
221  	    }
222  	
223  	    return s;
224  	  }
225  	
226  	  void add_update_sub(MonSession *s, const std::string& what, version_t start, bool onetime, bool incremental_onetime) {
227  	    Subscription *sub = 0;
228  	    if (s->sub_map.count(what)) {
229  	      sub = s->sub_map[what];
230  	    } else {
231  	      sub = new Subscription(s, what);
232  	      s->sub_map[what] = sub;
233  	
234  	      if (!subs.count(what))
235  		subs[what] = new xlist<Subscription*>;
236  	      subs[what]->push_back(&sub->type_item);
237  	    }
238  	    sub->next = start;
239  	    sub->onetime = onetime;
240  	    sub->incremental_onetime = onetime && incremental_onetime;
241  	  }
242  	
243  	  void remove_sub(Subscription *sub) {
244  	    sub->session->sub_map.erase(sub->type);
245  	    sub->type_item.remove_myself();
246  	    delete sub;
247  	  }
248  	};
249  	
250  	inline std::ostream& operator<<(std::ostream& out, const MonSession& s)
251  	{
252  	  out << "MonSession(" << s.name << " " << s.addrs
253  	      << " is " << (s.closed ? "closed" : "open")
254  	      << " " << s.caps
255  	      << ", features 0x" << std::hex << s.con_features << std::dec
256  	      <<  " (" << ceph_release_name(ceph_release_from_features(s.con_features))
257  	      << "))";
258  	  return out;
259  	}
260  	
261  	#endif
262