Migrate capability negotiation code to new dynamic capability management API.

This needs a lot of testing, obviously.
This commit is contained in:
William Pitcock 2012-02-04 01:47:46 -06:00
parent ec3a9055f2
commit 346fba9252
7 changed files with 175 additions and 309 deletions

View file

@ -28,6 +28,7 @@
#define INCLUDED_serv_h
#include "config.h"
#include "capability.h"
/*
* The number of seconds between calls to try_connections(). Fiddle with
@ -47,40 +48,35 @@ struct server_conf;
struct Channel;
/* Capabilities */
struct Capability
{
const char *name; /* name of capability */
unsigned int cap; /* mask value */
unsigned int required; /* 1 if required, 0 if not */
};
extern struct CapabilityIndex *serv_capindex;
#define CAP_CAP 0x00001 /* received a CAP to begin with */
#define CAP_QS 0x00002 /* Can handle quit storm removal */
#define CAP_EX 0x00004 /* Can do channel +e exemptions */
#define CAP_CHW 0x00008 /* Can do channel wall @# */
#define CAP_IE 0x00010 /* Can do invite exceptions */
#define CAP_KLN 0x00040 /* Can do KLINE message */
#define CAP_ZIP 0x00100 /* Can do ZIPlinks */
#define CAP_KNOCK 0x00400 /* supports KNOCK */
#define CAP_TB 0x00800 /* supports TBURST */
#define CAP_UNKLN 0x01000 /* supports remote unkline */
#define CAP_CLUSTER 0x02000 /* supports cluster stuff */
#define CAP_ENCAP 0x04000 /* supports ENCAP */
#define CAP_TS6 0x08000 /* supports TS6 or above */
#define CAP_SERVICE 0x10000
#define CAP_RSFNC 0x20000 /* rserv FNC */
#define CAP_SAVE 0x40000 /* supports SAVE (nick collision FNC) */
#define CAP_EUID 0x80000 /* supports EUID (ext UID + nonencap CHGHOST) */
#define CAP_EOPMOD 0x100000 /* supports EOPMOD (ext +z + ext topic) */
#define CAP_BAN 0x200000 /* supports propagated bans */
#define CAP_MLOCK 0x400000 /* supports MLOCK messages */
/*
* XXX: this is kind of ugly, but this allows us to have backwards
* API-compatibility.
*/
extern unsigned int CAP_CAP; /* received a CAP to begin with */
extern unsigned int CAP_QS; /* Can handle quit storm removal */
extern unsigned int CAP_EX; /* Can do channel +e exemptions */
extern unsigned int CAP_CHW; /* Can do channel wall @# */
extern unsigned int CAP_IE; /* Can do invite exceptions */
extern unsigned int CAP_KLN; /* Can do KLINE message */
extern unsigned int CAP_ZIP; /* Can do ZIPlinks */
extern unsigned int CAP_KNOCK; /* supports KNOCK */
extern unsigned int CAP_TB; /* supports TBURST */
extern unsigned int CAP_UNKLN; /* supports remote unkline */
extern unsigned int CAP_CLUSTER; /* supports cluster stuff */
extern unsigned int CAP_ENCAP; /* supports ENCAP */
extern unsigned int CAP_TS6; /* supports TS6 or above */
extern unsigned int CAP_SERVICE; /* supports services */
extern unsigned int CAP_RSFNC; /* rserv FNC */
extern unsigned int CAP_SAVE; /* supports SAVE (nick collision FNC) */
extern unsigned int CAP_EUID; /* supports EUID (ext UID + nonencap CHGHOST) */
extern unsigned int CAP_EOPMOD; /* supports EOPMOD (ext +z + ext topic) */
extern unsigned int CAP_BAN; /* supports propagated bans */
extern unsigned int CAP_MLOCK; /* supports MLOCK messages */
#define CAP_MASK (CAP_QS | CAP_EX | CAP_CHW | \
CAP_IE | CAP_KLN | CAP_SERVICE |\
CAP_CLUSTER | CAP_ENCAP | \
CAP_ZIP | CAP_KNOCK | CAP_UNKLN | \
CAP_RSFNC | CAP_SAVE | CAP_EUID | CAP_EOPMOD | \
CAP_BAN | CAP_MLOCK)
/* XXX: added for backwards compatibility. --nenolod */
#define CAP_MASK (capability_index_mask(serv_capindex) & ~(CAP_TS6 | CAP_CAP))
#ifdef HAVE_LIBZ
#define CAP_ZIP_SUPPORTED CAP_ZIP
@ -103,8 +99,6 @@ struct Capability
* because all servers that we talk to already do TS, and the kludged
* extra argument to "PASS" takes care of checking that. -orabidoo
*/
extern struct Capability captab[];
extern int MaxClientCount; /* GLOBAL - highest number of clients */
extern int MaxConnectionCount; /* GLOBAL - highest number of connections */
@ -117,11 +111,12 @@ extern int refresh_user_links;
#define HUNTED_ISME 0 /* if this server should execute the command */
#define HUNTED_PASS 1 /* if message passed onwards successfully */
extern void init_builtin_capabs(void);
extern int hunt_server(struct Client *client_pt,
struct Client *source_pt,
const char *command, int server, int parc, const char **parv);
extern void send_capabilities(struct Client *, int);
extern void send_capabilities(struct Client *, unsigned int);
extern const char *show_capabilities(struct Client *client);
extern void try_connections(void *unused);

View file

@ -109,6 +109,7 @@ mr_server(struct Client *client_p, struct Client *source_p, int parc, const char
return 0;
}
#ifdef NOTYET
/* check to ensure any "required" caps are set. --nenolod */
for (cap = captab; cap->name; cap++)
{
@ -125,6 +126,7 @@ mr_server(struct Client *client_p, struct Client *source_p, int parc, const char
return 0;
}
}
#endif
/* Now we just have to call check_server and everything should be
* check for us... -A1kmm. */

View file

@ -56,7 +56,6 @@ DECLARE_MODULE_AV1(capab, NULL, NULL, capab_clist, NULL, NULL, "$Revision: 1295
static int
mr_capab(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
struct Capability *cap;
int i;
char *p;
char *s;
@ -84,16 +83,7 @@ mr_capab(struct Client *client_p, struct Client *source_p, int parc, const char
{
char *t = LOCAL_COPY(parv[i]);
for (s = rb_strtok_r(t, " ", &p); s; s = rb_strtok_r(NULL, " ", &p))
{
for (cap = captab; cap->name; cap++)
{
if(!irccmp(cap->name, s))
{
client_p->localClient->caps |= cap->cap;
break;
}
}
}
client_p->localClient->caps |= capability_get(serv_capindex, s);
}
return 0;
@ -103,7 +93,6 @@ static int
me_gcap(struct Client *client_p, struct Client *source_p,
int parc, const char *parv[])
{
struct Capability *cap;
char *t = LOCAL_COPY(parv[1]);
char *s;
char *p;
@ -121,16 +110,7 @@ me_gcap(struct Client *client_p, struct Client *source_p,
source_p->serv->fullcaps = rb_strdup(parv[1]);
for (s = rb_strtok_r(t, " ", &p); s; s = rb_strtok_r(NULL, " ", &p))
{
for (cap = captab; cap->name; cap++)
{
if(!irccmp(cap->name, s))
{
source_p->serv->caps |= cap->cap;
break;
}
}
}
source_p->serv->caps |= capability_get(serv_capindex, s);
return 0;
}

View file

@ -50,16 +50,6 @@ static rb_bh *ban_heap;
static rb_bh *topic_heap;
static rb_bh *member_heap;
static int channel_capabs[] = { CAP_EX, CAP_IE,
CAP_SERVICE,
CAP_TS6
};
#define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
#define NCHCAP_COMBOS (1 << NCHCAPS)
static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
static void free_topic(struct Channel *chptr);
static int h_can_join;
@ -1198,102 +1188,6 @@ channel_modes(struct Channel *chptr, struct Client *client_p)
return final;
}
/* Now lets do some stuff to keep track of what combinations of
* servers exist...
* Note that the number of combinations doubles each time you add
* something to this list. Each one is only quick if no servers use that
* combination, but if the numbers get too high here MODE will get too
* slow. I suggest if you get more than 7 here, you consider getting rid
* of some and merging or something. If it wasn't for irc+cs we would
* probably not even need to bother about most of these, but unfortunately
* we do. -A1kmm
*/
/* void init_chcap_usage_counts(void)
*
* Inputs - none
* Output - none
* Side-effects - Initialises the usage counts to zero. Fills in the
* chcap_yes and chcap_no combination tables.
*/
void
init_chcap_usage_counts(void)
{
unsigned long m, c, y, n;
memset(chcap_combos, 0, sizeof(chcap_combos));
/* For every possible combination */
for (m = 0; m < NCHCAP_COMBOS; m++)
{
/* Check each capab */
for (c = y = n = 0; c < NCHCAPS; c++)
{
if((m & (1 << c)) == 0)
n |= channel_capabs[c];
else
y |= channel_capabs[c];
}
chcap_combos[m].cap_yes = y;
chcap_combos[m].cap_no = n;
}
}
/* void set_chcap_usage_counts(struct Client *serv_p)
* Input: serv_p; The client whose capabs to register.
* Output: none
* Side-effects: Increments the usage counts for the correct capab
* combination.
*/
void
set_chcap_usage_counts(struct Client *serv_p)
{
int n;
for (n = 0; n < NCHCAP_COMBOS; n++)
{
if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
NotCapable(serv_p, chcap_combos[n].cap_no))
{
chcap_combos[n].count++;
return;
}
}
/* This should be impossible -A1kmm. */
s_assert(0);
}
/* void set_chcap_usage_counts(struct Client *serv_p)
*
* Inputs - serv_p; The client whose capabs to register.
* Output - none
* Side-effects - Decrements the usage counts for the correct capab
* combination.
*/
void
unset_chcap_usage_counts(struct Client *serv_p)
{
int n;
for (n = 0; n < NCHCAP_COMBOS; n++)
{
if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
NotCapable(serv_p, chcap_combos[n].cap_no))
{
/* Hopefully capabs can't change dynamically or anything... */
s_assert(chcap_combos[n].count > 0);
if(chcap_combos[n].count > 0)
chcap_combos[n].count--;
return;
}
}
/* This should be impossible -A1kmm. */
s_assert(0);
}
/* void send_cap_mode_changes(struct Client *client_p,
* struct Client *source_p,
* struct Channel *chptr, int cap, int nocap)
@ -1305,6 +1199,9 @@ unset_chcap_usage_counts(struct Client *serv_p)
* Reverted back to my original design, except that we now keep a count
* of the number of servers which each combination as an optimisation, so
* the capabs combinations which are not needed are not worked out. -A1kmm
*
* Removed most code here because we don't need to be compatible with ircd
* 2.8.21+CSr and stuff. --nenolod
*/
void
send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
@ -1315,106 +1212,97 @@ send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
int i, mbl, pbl, nc, mc, preflen, len;
char *pbuf;
const char *arg;
int dir;
int j;
int cap;
int nocap;
int dir;
int arglen;
/* Now send to servers... */
for (j = 0; j < NCHCAP_COMBOS; j++)
mc = 0;
nc = 0;
pbl = 0;
parabuf[0] = 0;
pbuf = parabuf;
dir = MODE_QUERY;
mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
use_id(source_p), (long) chptr->channelts,
chptr->chname);
/* loop the list of - modes we have */
for (i = 0; i < mode_count; i++)
{
if(chcap_combos[j].count == 0)
/* if they dont support the cap we need, or they do support a cap they
* cant have, then dont add it to the modebuf.. that way they wont see
* the mode
*/
if (mode_changes[i].letter == 0)
continue;
mc = 0;
nc = 0;
pbl = 0;
parabuf[0] = 0;
pbuf = parabuf;
dir = MODE_QUERY;
cap = mode_changes[i].caps;
nocap = mode_changes[i].nocaps;
cap = chcap_combos[j].cap_yes;
nocap = chcap_combos[j].cap_no;
if (!EmptyString(mode_changes[i].id))
arg = mode_changes[i].id;
else
arg = mode_changes[i].arg;
mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
use_id(source_p), (long) chptr->channelts,
chptr->chname);
/* loop the list of - modes we have */
for (i = 0; i < mode_count; i++)
if(arg)
{
/* if they dont support the cap we need, or they do support a cap they
* cant have, then dont add it to the modebuf.. that way they wont see
* the mode
*/
if((mode_changes[i].letter == 0) ||
((cap & mode_changes[i].caps) != mode_changes[i].caps)
|| ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
arglen = strlen(arg);
/* dont even think about it! --fl */
if(arglen > MODEBUFLEN - 5)
continue;
if(!EmptyString(mode_changes[i].id))
arg = mode_changes[i].id;
else
arg = mode_changes[i].arg;
if(arg)
{
arglen = strlen(arg);
/* dont even think about it! --fl */
if(arglen > MODEBUFLEN - 5)
continue;
}
/* if we're creeping past the buf size, we need to send it and make
* another line for the other modes
* XXX - this could give away server topology with uids being
* different lengths, but not much we can do, except possibly break
* them as if they were the longest of the nick or uid at all times,
* which even then won't work as we don't always know the uid -A1kmm.
*/
if(arg && ((mc == MAXMODEPARAMSSERV) ||
((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
{
if(nc != 0)
sendto_server(client_p, chptr, cap, nocap,
"%s %s", modebuf, parabuf);
nc = 0;
mc = 0;
mbl = preflen;
pbl = 0;
pbuf = parabuf;
parabuf[0] = 0;
dir = MODE_QUERY;
}
if(dir != mode_changes[i].dir)
{
modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
dir = mode_changes[i].dir;
}
modebuf[mbl++] = mode_changes[i].letter;
modebuf[mbl] = 0;
nc++;
if(arg != NULL)
{
len = rb_sprintf(pbuf, "%s ", arg);
pbuf += len;
pbl += len;
mc++;
}
}
if(pbl && parabuf[pbl - 1] == ' ')
parabuf[pbl - 1] = 0;
/* if we're creeping past the buf size, we need to send it and make
* another line for the other modes
* XXX - this could give away server topology with uids being
* different lengths, but not much we can do, except possibly break
* them as if they were the longest of the nick or uid at all times,
* which even then won't work as we don't always know the uid -A1kmm.
*/
if(arg && ((mc == MAXMODEPARAMSSERV) ||
((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
{
if(nc != 0)
sendto_server(client_p, chptr, cap, nocap,
"%s %s", modebuf, parabuf);
nc = 0;
mc = 0;
if(nc != 0)
sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
mbl = preflen;
pbl = 0;
pbuf = parabuf;
parabuf[0] = 0;
dir = MODE_QUERY;
}
if(dir != mode_changes[i].dir)
{
modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
dir = mode_changes[i].dir;
}
modebuf[mbl++] = mode_changes[i].letter;
modebuf[mbl] = 0;
nc++;
if(arg != NULL)
{
len = rb_sprintf(pbuf, "%s ", arg);
pbuf += len;
pbl += len;
mc++;
}
}
if(pbl && parabuf[pbl - 1] == ' ')
parabuf[pbl - 1] = 0;
if(nc != 0)
sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
}
void

View file

@ -1326,7 +1326,6 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
rb_dlinkDelete(&source_p->localClient->tnode, &serv_list);
rb_dlinkFindDestroy(source_p, &global_serv_list);
unset_chcap_usage_counts(source_p);
sendk = source_p->localClient->sendK;
recvk = source_p->localClient->receiveK;

View file

@ -112,7 +112,7 @@ int zlib_ok = 1;
int testing_conf = 0;
time_t startup_time;
int default_server_capabs = CAP_MASK;
int default_server_capabs;
int splitmode;
int splitchecking;
@ -584,9 +584,6 @@ main(int argc, char *argv[])
memset(&AdminInfo, 0, sizeof(AdminInfo));
memset(&ServerStats, 0, sizeof(struct ServerStatistics));
/* Initialise the channel capability usage counts... */
init_chcap_usage_counts();
if(printVersion)
{
printf("ircd: version %s(%s)\n", ircd_version, serno);
@ -597,8 +594,6 @@ main(int argc, char *argv[])
exit(EXIT_SUCCESS);
}
setup_signals();
if (testing_conf)
@ -637,6 +632,9 @@ main(int argc, char *argv[])
seed_random(NULL);
init_builtin_capabs();
default_server_capabs = CAP_MASK;
init_main_logfile();
newconf_init();
init_s_conf();

View file

@ -54,6 +54,7 @@
#include "msg.h"
#include "reject.h"
#include "sslproc.h"
#include "capability.h"
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned int) 0xffffffff)
@ -70,28 +71,56 @@ 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 Capability captab[] = {
/* name cap */
{ "QS", CAP_QS },
{ "EX", CAP_EX },
{ "CHW", CAP_CHW},
{ "IE", CAP_IE},
{ "KLN", CAP_KLN},
{ "KNOCK", CAP_KNOCK},
{ "ZIP", CAP_ZIP},
{ "TB", CAP_TB},
{ "UNKLN", CAP_UNKLN},
{ "CLUSTER", CAP_CLUSTER},
{ "ENCAP", CAP_ENCAP },
{ "SERVICES", CAP_SERVICE },
{ "RSFNC", CAP_RSFNC },
{ "SAVE", CAP_SAVE },
{ "EUID", CAP_EUID },
{ "EOPMOD", CAP_EOPMOD },
{ "BAN", CAP_BAN },
{ "MLOCK", CAP_MLOCK },
{0, 0}
};
struct CapabilityIndex *serv_capindex = NULL;
unsigned int CAP_CAP;
unsigned int CAP_QS;
unsigned int CAP_EX;
unsigned int CAP_CHW;
unsigned int CAP_IE;
unsigned int CAP_KLN;
unsigned int CAP_ZIP;
unsigned int CAP_KNOCK;
unsigned int CAP_TB;
unsigned int CAP_UNKLN;
unsigned int CAP_CLUSTER;
unsigned int CAP_ENCAP;
unsigned int CAP_TS6;
unsigned int CAP_SERVICE;
unsigned int CAP_RSFNC;
unsigned int CAP_SAVE;
unsigned int CAP_EUID;
unsigned int CAP_EOPMOD;
unsigned int CAP_BAN;
unsigned int CAP_MLOCK;
/*
* initialize our builtin capability table. --nenolod
*/
void
init_builtin_capabs(void)
{
serv_capindex = capability_index_create();
CAP_QS = capability_put(serv_capindex, "QS");
CAP_EX = capability_put(serv_capindex, "EX");
CAP_CHW = capability_put(serv_capindex, "CHW");
CAP_IE = capability_put(serv_capindex, "IE");
CAP_KLN = capability_put(serv_capindex, "KLN");
CAP_KNOCK = capability_put(serv_capindex, "KNOCK");
CAP_ZIP = capability_put(serv_capindex, "ZIP");
CAP_TB = capability_put(serv_capindex, "TB");
CAP_UNKLN = capability_put(serv_capindex, "UNKLN");
CAP_CLUSTER = capability_put(serv_capindex, "CLUSTER");
CAP_ENCAP = capability_put(serv_capindex, "ENCAP");
CAP_SERVICE = capability_put(serv_capindex, "SERVICES");
CAP_RSFNC = capability_put(serv_capindex, "RSFNC");
CAP_SAVE = capability_put(serv_capindex, "SAVE");
CAP_EUID = capability_put(serv_capindex, "EUID");
CAP_EOPMOD = capability_put(serv_capindex, "EOPMOD");
CAP_BAN = capability_put(serv_capindex, "BAN");
CAP_MLOCK = capability_put(serv_capindex, "MLOCK");
}
static CNCB serv_connect_callback;
static CNCB serv_connect_ssl_callback;
@ -380,28 +409,9 @@ check_server(const char *name, struct Client *client_p)
*
*/
void
send_capabilities(struct Client *client_p, int cap_can_send)
send_capabilities(struct Client *client_p, unsigned int cap_can_send)
{
struct Capability *cap;
char msgbuf[BUFSIZE];
char *t;
int tl;
t = msgbuf;
for (cap = captab; cap->name; ++cap)
{
if(cap->cap & cap_can_send)
{
tl = rb_sprintf(t, "%s ", cap->name);
t += tl;
}
}
t--;
*t = '\0';
sendto_one(client_p, "CAPAB :%s", msgbuf);
sendto_one(client_p, "CAPAB :%s", capability_index_list(serv_capindex, cap_can_send));
}
static void
@ -693,7 +703,8 @@ const char *
show_capabilities(struct Client *target_p)
{
static char msgbuf[BUFSIZE];
struct Capability *cap;
*msgbuf = '\0';
if(has_id(target_p))
rb_strlcpy(msgbuf, " TS6", sizeof(msgbuf));
@ -704,11 +715,7 @@ show_capabilities(struct Client *target_p)
if(!IsServer(target_p) || !target_p->serv->caps) /* short circuit if no caps */
return msgbuf + 1;
for (cap = captab; cap->cap; ++cap)
{
if(cap->cap & target_p->serv->caps)
rb_snprintf_append(msgbuf, sizeof(msgbuf), " %s", cap->name);
}
rb_strlcat(msgbuf, capability_index_list(serv_capindex, target_p->serv->caps), sizeof(msgbuf));
return msgbuf + 1;
}
@ -804,9 +811,6 @@ server_estab(struct Client *client_p)
SetServer(client_p);
/* Update the capability combination usage counts */
set_chcap_usage_counts(client_p);
rb_dlinkAdd(client_p, &client_p->lnode, &me.serv->servers);
rb_dlinkMoveNode(&client_p->localClient->tnode, &unknown_list, &serv_list);
rb_dlinkAddTailAlloc(client_p, &global_serv_list);