mirror of
https://github.com/matrix-construct/construct
synced 2025-01-13 08:23:56 +01:00
ircd: Towards a comprehensive capability C -> C++ refactor.
This commit is contained in:
parent
10946db85e
commit
fb8792da3d
8 changed files with 171 additions and 156 deletions
|
@ -1,5 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Charybdis development team
|
||||
* Copyright (c) 2012 - 2016 William Pitcock <nenolod@dereferenced.org>.
|
||||
* Copyright (c) 2016 Jason Volk <jason@zemos.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -18,46 +20,48 @@
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __CAPABILITY_H__
|
||||
#define __CAPABILITY_H__
|
||||
#pragma once
|
||||
#define HAVE_IRCD_CAPABILITY_H
|
||||
|
||||
#include "stdinc.h"
|
||||
#ifdef __cplusplus
|
||||
namespace ircd {
|
||||
namespace capability {
|
||||
|
||||
struct CapabilityEntry {
|
||||
struct entry
|
||||
{
|
||||
std::string cap;
|
||||
unsigned int value;
|
||||
uint32_t value;
|
||||
bool require;
|
||||
bool orphan;
|
||||
void *ownerdata;
|
||||
void *ownerdata; //TODO: inheritance model
|
||||
|
||||
CapabilityEntry(std::string cap_, unsigned int value_, void *ownerdata_)
|
||||
: cap(cap_), value(value_), require(false), orphan(false), ownerdata(ownerdata_) { }
|
||||
entry(const std::string &cap, const uint32_t &value, void *const &ownerdata);
|
||||
};
|
||||
|
||||
struct CapabilityIndex {
|
||||
struct index
|
||||
{
|
||||
std::string name;
|
||||
std::map<std::string, std::shared_ptr<CapabilityEntry>, case_insensitive_less> cap_dict;
|
||||
unsigned int highest_bit;
|
||||
uint32_t highest_bit;
|
||||
std::list<index *>::iterator indexes_it;
|
||||
std::map<std::string, std::shared_ptr<entry>, case_insensitive_less> caps;
|
||||
|
||||
CapabilityIndex(std::string name_);
|
||||
~CapabilityIndex();
|
||||
void stats(void (*cb)(const std::string &line, void *privdata), void *privdata) const;
|
||||
std::string list(const uint32_t &cap_mask);
|
||||
uint32_t required();
|
||||
uint32_t mask();
|
||||
|
||||
std::shared_ptr<CapabilityEntry> find(std::string cap_name);
|
||||
bool orphan(const std::string &cap_name);
|
||||
bool require(const std::string &cap_name);
|
||||
uint32_t get(const std::string &cap_name, void **ownerdata);
|
||||
uint32_t put(const std::string &cap_name = "", void *ownerdata = nullptr);
|
||||
uint32_t put_anonymous();
|
||||
|
||||
unsigned int get(std::string cap_name, void **ownerdata);
|
||||
unsigned int put(std::string cap_name, void *ownerdata);
|
||||
unsigned int put_anonymous();
|
||||
|
||||
void orphan(std::string cap_name);
|
||||
void require(std::string cap_name);
|
||||
|
||||
void stats(void (*cb)(std::string &line, void *privdata), void *privdata);
|
||||
|
||||
const char *list(unsigned int cap_mask);
|
||||
unsigned int mask();
|
||||
unsigned int required();
|
||||
index(const std::string &name);
|
||||
~index();
|
||||
};
|
||||
|
||||
extern void capability_stats(void (*cb)(std::string &line, void *privdata), void *privdata);
|
||||
void stats(void (*cb)(const std::string &line, void *privdata), void *privdata);
|
||||
|
||||
#endif
|
||||
} // namespace capability
|
||||
} // namespace ircd
|
||||
#endif // __cplusplus
|
||||
|
|
|
@ -46,8 +46,8 @@ struct server_conf;
|
|||
struct Channel;
|
||||
|
||||
/* Capabilities */
|
||||
extern struct CapabilityIndex serv_capindex;
|
||||
extern struct CapabilityIndex cli_capindex;
|
||||
extern ircd::capability::index serv_capindex; //TODO: namespace
|
||||
extern ircd::capability::index cli_capindex; //TODO: namespace
|
||||
|
||||
/* register client capabilities with this structure for 3.2 enhanced capability negotiation */
|
||||
#define CLICAP_FLAGS_STICKY 0x001
|
||||
|
|
|
@ -23,138 +23,127 @@
|
|||
#include <ircd/s_assert.h>
|
||||
#include <rb/format.h>
|
||||
|
||||
static std::list<CapabilityIndex *> capability_indexes;
|
||||
using namespace ircd::capability;
|
||||
|
||||
CapabilityIndex::CapabilityIndex(std::string name_) : name(name_), highest_bit(1)
|
||||
|
||||
std::list<capability::index *> indexes;
|
||||
|
||||
|
||||
entry::entry(const std::string &cap,
|
||||
const uint32_t &value,
|
||||
void *const &ownerdata)
|
||||
:cap(cap)
|
||||
,value(value)
|
||||
,require(false)
|
||||
,orphan(false)
|
||||
,ownerdata(ownerdata)
|
||||
{
|
||||
capability_indexes.push_back(this);
|
||||
}
|
||||
|
||||
CapabilityIndex::~CapabilityIndex()
|
||||
|
||||
index::index(const std::string &name)
|
||||
:name(name)
|
||||
,highest_bit(1)
|
||||
,indexes_it(indexes.emplace(end(indexes), this))
|
||||
{
|
||||
for (auto it = capability_indexes.begin(); it != capability_indexes.end(); it++)
|
||||
{
|
||||
if (*it == this)
|
||||
{
|
||||
capability_indexes.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<CapabilityEntry>
|
||||
CapabilityIndex::find(std::string cap)
|
||||
index::~index()
|
||||
{
|
||||
return cap_dict[cap];
|
||||
indexes.erase(indexes_it);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
CapabilityIndex::get(std::string cap, void **ownerdata)
|
||||
uint32_t
|
||||
index::put(const std::string &cap,
|
||||
void *ownerdata)
|
||||
{
|
||||
std::shared_ptr<CapabilityEntry> entry;
|
||||
|
||||
entry = find(cap);
|
||||
if (entry != NULL && !entry->orphan)
|
||||
{
|
||||
if (ownerdata != NULL)
|
||||
*ownerdata = entry->ownerdata;
|
||||
return (1 << entry->value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
CapabilityIndex::put(std::string cap, void *ownerdata)
|
||||
{
|
||||
std::shared_ptr<CapabilityEntry> entry;
|
||||
|
||||
if (highest_bit == 0)
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
if ((entry = find(cap)) != NULL)
|
||||
auto it(caps.lower_bound(cap));
|
||||
if (it != end(caps) && it->second->cap == cap)
|
||||
{
|
||||
auto &entry(it->second);
|
||||
entry->orphan = false;
|
||||
return (1 << entry->value);
|
||||
return 1 << entry->value;
|
||||
}
|
||||
|
||||
entry = cap_dict[cap] = std::make_shared<CapabilityEntry>(cap, highest_bit, ownerdata);
|
||||
auto entry(std::make_shared<entry>(cap, highest_bit, ownerdata));
|
||||
caps.emplace_hint(it, cap, entry);
|
||||
|
||||
highest_bit++;
|
||||
if (highest_bit % (sizeof(unsigned int) * 8) == 0)
|
||||
if (highest_bit % (sizeof(uint32_t) * 8) == 0)
|
||||
highest_bit = 0;
|
||||
|
||||
return (1 << entry->value);
|
||||
return 1 << entry->value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
CapabilityIndex::put_anonymous()
|
||||
uint32_t
|
||||
index::put_anonymous()
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
if (!highest_bit)
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
value = 1 << highest_bit;
|
||||
const uint32_t value(1 << highest_bit);
|
||||
highest_bit++;
|
||||
if (highest_bit % (sizeof(unsigned int) * 8) == 0)
|
||||
if (highest_bit % (sizeof(uint32_t) * 8) == 0)
|
||||
highest_bit = 0;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
CapabilityIndex::orphan(std::string cap)
|
||||
uint32_t
|
||||
index::get(const std::string &cap,
|
||||
void **ownerdata)
|
||||
try
|
||||
{
|
||||
std::shared_ptr<CapabilityEntry> entry;
|
||||
auto &entry(caps.at(cap));
|
||||
if (entry->orphan)
|
||||
return 0;
|
||||
|
||||
entry = cap_dict[cap];
|
||||
if (entry != NULL)
|
||||
{
|
||||
entry->require = false;
|
||||
entry->orphan = true;
|
||||
entry->ownerdata = NULL;
|
||||
}
|
||||
if (ownerdata != NULL)
|
||||
*ownerdata = entry->ownerdata;
|
||||
|
||||
return 1 << entry->value;
|
||||
}
|
||||
catch(const std::out_of_range &e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CapabilityIndex::require(std::string cap)
|
||||
bool
|
||||
index::require(const std::string &cap)
|
||||
{
|
||||
std::shared_ptr<CapabilityEntry> entry;
|
||||
const auto it(caps.find(cap));
|
||||
if (it == end(caps))
|
||||
return false;
|
||||
|
||||
entry = cap_dict[cap];
|
||||
if (entry != NULL)
|
||||
entry->require = true;
|
||||
auto &entry(it->second);
|
||||
entry->require = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *
|
||||
CapabilityIndex::list(unsigned int cap_mask)
|
||||
bool
|
||||
index::orphan(const std::string &cap)
|
||||
{
|
||||
static std::string buf;
|
||||
const auto it(caps.find(cap));
|
||||
if (it == end(caps))
|
||||
return false;
|
||||
|
||||
buf.clear();
|
||||
|
||||
for (auto it = cap_dict.begin(); it != cap_dict.end(); it++)
|
||||
{
|
||||
auto entry = it->second;
|
||||
|
||||
if ((1 << entry->value) & cap_mask)
|
||||
{
|
||||
buf += entry->cap + " ";
|
||||
}
|
||||
}
|
||||
|
||||
return buf.c_str();
|
||||
auto &entry(it->second);
|
||||
entry->require = false;
|
||||
entry->orphan = true;
|
||||
entry->ownerdata = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
CapabilityIndex::mask()
|
||||
uint32_t
|
||||
index::mask()
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
|
||||
for (auto it = cap_dict.begin(); it != cap_dict.end(); it++)
|
||||
uint32_t mask(0);
|
||||
for (const auto &it : caps)
|
||||
{
|
||||
auto entry = it->second;
|
||||
const auto &entry(it.second);
|
||||
if (!entry->orphan)
|
||||
mask |= (1 << entry->value);
|
||||
}
|
||||
|
@ -162,14 +151,13 @@ CapabilityIndex::mask()
|
|||
return mask;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
CapabilityIndex::required()
|
||||
uint32_t
|
||||
index::required()
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
|
||||
for (auto it = cap_dict.begin(); it != cap_dict.end(); it++)
|
||||
uint32_t mask(0);
|
||||
for (const auto &it : caps)
|
||||
{
|
||||
auto entry = it->second;
|
||||
const auto &entry(it.second);
|
||||
if (!entry->orphan && entry->require)
|
||||
mask |= (1 << entry->value);
|
||||
}
|
||||
|
@ -177,20 +165,34 @@ CapabilityIndex::required()
|
|||
return mask;
|
||||
}
|
||||
|
||||
void
|
||||
CapabilityIndex::stats(void (*cb)(std::string &line, void *privdata), void *privdata)
|
||||
std::string
|
||||
index::list(const uint32_t &cap_mask)
|
||||
{
|
||||
std::string out = fmt::format("'{0}': {1} allocated:", name, highest_bit - 1);
|
||||
std::stringstream buf;
|
||||
for (const auto &it : caps)
|
||||
{
|
||||
const auto &entry(it.second);
|
||||
if ((1 << entry->value) & cap_mask)
|
||||
buf << entry->cap << " ";
|
||||
}
|
||||
|
||||
for (auto it = cap_dict.begin(); it != cap_dict.end(); it++)
|
||||
out += fmt::format(" {0}<{1}>", it->first, it->second->value);
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
void
|
||||
index::stats(void (*cb)(const std::string &line, void *privdata), void *privdata)
|
||||
const
|
||||
{
|
||||
std::string out(fmt::format("'{0}': {1} allocated:", name, highest_bit - 1));
|
||||
for (const auto &it : caps)
|
||||
out += fmt::format(" {0}<{1}>", it.first, it.second->value);
|
||||
|
||||
cb(out, privdata);
|
||||
}
|
||||
|
||||
void
|
||||
capability_stats(void (*cb)(std::string &line, void *privdata), void *privdata)
|
||||
capability::stats(void (*cb)(const std::string &line, void *privdata), void *privdata)
|
||||
{
|
||||
for (auto it = capability_indexes.begin(); it != capability_indexes.end(); it++)
|
||||
(*it)->stats(cb, privdata);
|
||||
for (const auto &index : indexes)
|
||||
index->stats(cb, privdata);
|
||||
}
|
||||
|
|
|
@ -364,7 +364,9 @@ static
|
|||
bool init_module__cap(struct module *const mod,
|
||||
mapi_cap_list_av2 *const m)
|
||||
{
|
||||
struct CapabilityIndex *idx;
|
||||
using ircd::capability::index;
|
||||
|
||||
index *idx;
|
||||
switch(m->cap_index)
|
||||
{
|
||||
case MAPI_CAP_CLIENT: idx = &cli_capindex; break;
|
||||
|
@ -392,7 +394,9 @@ static
|
|||
void fini_module__cap(struct module *const mod,
|
||||
mapi_cap_list_av2 *const m)
|
||||
{
|
||||
struct CapabilityIndex *idx;
|
||||
using ircd::capability::index;
|
||||
|
||||
index *idx;
|
||||
switch(m->cap_index)
|
||||
{
|
||||
case MAPI_CAP_CLIENT: idx = &cli_capindex; break;
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
#include <ircd/capability.h>
|
||||
#include <ircd/s_assert.h>
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
int MaxConnectionCount = 1;
|
||||
int MaxClientCount = 1;
|
||||
int refresh_user_links = 0;
|
||||
|
@ -64,8 +66,8 @@ static char buf[BUFSIZE];
|
|||
* because all servers that we talk to already do TS, and the kludged
|
||||
* extra argument to "PASS" takes care of checking that. -orabidoo
|
||||
*/
|
||||
struct CapabilityIndex serv_capindex {"server capabilities"};
|
||||
struct CapabilityIndex cli_capindex {"client capabilities"};
|
||||
capability::index serv_capindex {"server capabilities"};
|
||||
capability::index cli_capindex {"client capabilities"};
|
||||
|
||||
unsigned int CAP_CAP;
|
||||
unsigned int CAP_QS;
|
||||
|
@ -458,7 +460,7 @@ check_server(const char *name, struct Client *client_p)
|
|||
void
|
||||
send_capabilities(struct Client *client_p, unsigned int cap_can_send)
|
||||
{
|
||||
sendto_one(client_p, "CAPAB :%s", serv_capindex.list(cap_can_send));
|
||||
sendto_one(client_p, "CAPAB :%s", serv_capindex.list(cap_can_send).c_str());
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -766,7 +768,7 @@ show_capabilities(struct Client *target_p)
|
|||
return msgbuf + 1;
|
||||
|
||||
rb_strlcat(msgbuf, " ", sizeof(msgbuf));
|
||||
rb_strlcat(msgbuf, serv_capindex.list(target_p->serv->caps), sizeof(msgbuf));
|
||||
rb_strlcat(msgbuf, serv_capindex.list(target_p->serv->caps).c_str(), sizeof(msgbuf));
|
||||
|
||||
return msgbuf + 1;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,6 @@ mr_server(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sourc
|
|||
struct Client *target_p;
|
||||
int hop;
|
||||
unsigned int required_mask;
|
||||
const char *missing;
|
||||
int ret;
|
||||
|
||||
name = parv[1];
|
||||
|
@ -222,18 +221,18 @@ mr_server(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sourc
|
|||
required_mask = serv_capindex.required();
|
||||
if (!IsCapable(client_p, required_mask))
|
||||
{
|
||||
missing = serv_capindex.list(required_mask & ~client_p->localClient->caps);
|
||||
const auto missing(serv_capindex.list(required_mask & ~client_p->localClient->caps));
|
||||
sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
|
||||
"Link %s dropped, required CAPABs [%s] are missing",
|
||||
name, missing);
|
||||
name, missing.c_str());
|
||||
ilog(L_SERVER, "Link %s%s dropped, required CAPABs [%s] are missing",
|
||||
EmptyString(client_p->name) ? name : "",
|
||||
log_client_name(client_p, SHOW_IP), missing);
|
||||
log_client_name(client_p, SHOW_IP), missing.c_str());
|
||||
/* Do not use '[' in the below message because it would cause
|
||||
* it to be considered potentially unsafe (might disclose IP
|
||||
* addresses)
|
||||
*/
|
||||
sendto_one(client_p, "ERROR :Missing required CAPABs (%s)", missing);
|
||||
sendto_one(client_p, "ERROR :Missing required CAPABs (%s)", missing.c_str());
|
||||
exit_client(client_p, client_p, client_p, "Missing required CAPABs");
|
||||
|
||||
return;
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#include <ircd/s_conf.h>
|
||||
#include <ircd/hash.h>
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char cap_desc[] = "Provides the commands used for client capability negotiation";
|
||||
|
||||
typedef int (*bqcmp)(const void *, const void *);
|
||||
|
@ -63,7 +65,7 @@ DECLARE_MODULE_AV2(cap, NULL, NULL, cap_clist, NULL, NULL, NULL, NULL, cap_desc)
|
|||
#define HasCapabilityFlag(c, f) (c->ownerdata != NULL && (((struct ClientCapability *)c->ownerdata)->flags & (f)) == f)
|
||||
|
||||
static inline int
|
||||
clicap_visible(struct Client *client_p, const std::shared_ptr<CapabilityEntry> cap)
|
||||
clicap_visible(struct Client *client_p, const std::shared_ptr<capability::entry> cap)
|
||||
{
|
||||
struct ClientCapability *clicap;
|
||||
|
||||
|
@ -89,12 +91,11 @@ clicap_visible(struct Client *client_p, const std::shared_ptr<CapabilityEntry> c
|
|||
* int pointer to whether we finish with success
|
||||
* Ouputs: Cap entry if found, NULL otherwise.
|
||||
*/
|
||||
static std::shared_ptr<CapabilityEntry>
|
||||
static std::shared_ptr<capability::entry>
|
||||
clicap_find(const char *data, int *negate, int *finished)
|
||||
{
|
||||
static char buf[BUFSIZE];
|
||||
static char *p;
|
||||
std::shared_ptr<CapabilityEntry> cap;
|
||||
char *s;
|
||||
|
||||
*negate = 0;
|
||||
|
@ -131,15 +132,16 @@ clicap_find(const char *data, int *negate, int *finished)
|
|||
if((s = strchr(p, ' ')))
|
||||
*s++ = '\0';
|
||||
|
||||
if((cap = cli_capindex.find(p)) != NULL)
|
||||
{
|
||||
if(s)
|
||||
p = s;
|
||||
else
|
||||
*finished = 1;
|
||||
}
|
||||
const auto it(cli_capindex.caps.find(p));
|
||||
if (it == end(cli_capindex.caps))
|
||||
return {};
|
||||
|
||||
return cap;
|
||||
if (s)
|
||||
p = s;
|
||||
else
|
||||
*finished = 1;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/* clicap_generate()
|
||||
|
@ -170,10 +172,10 @@ clicap_generate(struct Client *source_p, const char *subcmd, int flags)
|
|||
return;
|
||||
}
|
||||
|
||||
for (auto it = cli_capindex.cap_dict.begin(); it != cli_capindex.cap_dict.end(); it++)
|
||||
for (const auto &it : cli_capindex.caps)
|
||||
{
|
||||
size_t caplen = 0;
|
||||
const auto entry = it->second;
|
||||
const auto &entry(it.second);
|
||||
const auto clicap(reinterpret_cast<ClientCapability *>(entry->ownerdata));
|
||||
const char *data = NULL;
|
||||
|
||||
|
@ -217,7 +219,7 @@ clicap_generate(struct Client *source_p, const char *subcmd, int flags)
|
|||
static void
|
||||
cap_ack(struct Client *source_p, const char *arg)
|
||||
{
|
||||
std::shared_ptr<CapabilityEntry> cap;
|
||||
std::shared_ptr<capability::entry> cap;
|
||||
int capadd = 0, capdel = 0;
|
||||
int finished = 0, negate;
|
||||
|
||||
|
@ -290,7 +292,7 @@ cap_req(struct Client *source_p, const char *arg)
|
|||
{
|
||||
char buf[BUFSIZE];
|
||||
char pbuf[2][BUFSIZE];
|
||||
std::shared_ptr<CapabilityEntry> cap;
|
||||
std::shared_ptr<capability::entry> cap;
|
||||
int buflen, plen;
|
||||
int i = 0;
|
||||
int capadd = 0, capdel = 0;
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include <ircd/whowas.h>
|
||||
#include <ircd/sslproc.h>
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char stats_desc[] =
|
||||
"Provides the STATS command to inspect various server/network information";
|
||||
|
||||
|
@ -819,7 +821,7 @@ stats_oper(struct Client *source_p)
|
|||
}
|
||||
|
||||
static void
|
||||
stats_capability_walk(std::string &line, void *data)
|
||||
stats_capability_walk(const std::string &line, void *data)
|
||||
{
|
||||
struct Client *client_p = (Client *)data;
|
||||
|
||||
|
@ -829,7 +831,7 @@ stats_capability_walk(std::string &line, void *data)
|
|||
static void
|
||||
stats_capability(struct Client *client_p)
|
||||
{
|
||||
capability_stats(stats_capability_walk, client_p);
|
||||
capability::stats(stats_capability_walk, client_p);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in a new issue