Implement the netsplit batch type.

This also lays the groundwork for the netjoin batch type, but that isn't
implemented yet. I don't like how some of this is implemented but it'll
have to do for now...

Compile tested, needs more testing.
This commit is contained in:
Elizabeth Myers 2016-04-15 16:50:43 -05:00
parent 4f2b9a4fd1
commit 2373891299
No known key found for this signature in database
GPG key ID: 1A10EF78D83E317B
8 changed files with 346 additions and 1 deletions

47
include/batch.h Normal file
View file

@ -0,0 +1,47 @@
/* ircd/batch.h - batch management
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdinc.h"
#include "client.h"
typedef enum
{
BATCH_NETSPLIT,
BATCH_NETJOIN,
BATCH_LAST,
} batch_type;
/* Used for netsplits/netjoins */
struct Batch
{
batch_type batch; /* Type of batch */
char id[8]; /* Id of batch */
void *data; /* Batch-specific data */
void *pdata; /* Private data */
int parc; /* Batch parameter count */
char **parv; /* Batch parameters */
rb_dlink_node node;
};
struct Batch *start_batch(batch_type batch, void *data, int parc, ...);
void finish_batch(struct Batch *batch_p);
struct Batch *find_batch(batch_type batch, void *data);

View file

@ -68,6 +68,7 @@ extern unsigned int CLICAP_USERHOST_IN_NAMES;
extern unsigned int CLICAP_CAP_NOTIFY; extern unsigned int CLICAP_CAP_NOTIFY;
extern unsigned int CLICAP_CHGHOST; extern unsigned int CLICAP_CHGHOST;
extern unsigned int CLICAP_ECHO_MESSAGE; extern unsigned int CLICAP_ECHO_MESSAGE;
extern unsigned int CLICAP_BATCH;
/* /*
* XXX: this is kind of ugly, but this allows us to have backwards * XXX: this is kind of ugly, but this allows us to have backwards

View file

@ -21,6 +21,7 @@ endif
libircd_la_SOURCES = \ libircd_la_SOURCES = \
authproc.c \ authproc.c \
bandbi.c \ bandbi.c \
batch.c \
cache.c \ cache.c \
capability.c \ capability.c \
channel.c \ channel.c \

202
ircd/batch.c Normal file
View file

@ -0,0 +1,202 @@
/* ircd/batch.c - batch management
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdinc.h"
#include "batch.h"
#include "client.h"
#include "s_serv.h"
#include "send.h"
#include "channel.h"
#include "hash.h"
#include "s_assert.h"
#include "rb_radixtree.h"
/* Multiple batches may be in progress for each slot. */
rb_dlink_list batches[BATCH_LAST];
static inline void
generate_batch_id(char *ptr, size_t len)
{
size_t i;
const char batchchars[65] =
"\0._0123456789" /* Zero-indexed */
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
len--; /* Room for \0 */
for(i = 0; i < len; i++)
{
char r;
do
{
r = batchchars[rand() & 0x7F]; /* random int between 0-64 */
if(r == '\0' && i > 3)
/* We have enough chars */
goto end;
} while(r == '\0');
ptr[i] = r;
}
end:
ptr[i] = '\0';
}
struct Batch *
start_batch(batch_type batch, void *data, int parc, ...)
{
struct Batch *batch_p = rb_malloc(sizeof(struct Batch));
batch_p->batch = batch;
generate_batch_id(batch_p->id, sizeof(batch_p->id));
batch_p->data = data;
batch_p->parc = parc;
if(parc > 0)
{
/* Get the argument list */
va_list args;
batch_p->parv = rb_malloc(sizeof(char *) * parc);
va_start(args, parc);
for(size_t i = 0; i < parc; i++)
batch_p->parv[i] = va_arg(args, char *);
va_end(args);
}
/* Batch-type specific processing */
switch(batch)
{
case BATCH_NETSPLIT:
case BATCH_NETJOIN:
{
/* Build list of channels affected by the batch */
rb_dlink_list *clist;
rb_radixtree_iteration_state iter;
struct Channel *chptr;
batch_p->pdata = clist = rb_malloc(sizeof(rb_dlink_list));
/* Look for channels we need to send the batch to */
RB_RADIXTREE_FOREACH(chptr, &iter, channel_tree)
{
rb_dlink_node *ptr;
if(rb_dlink_list_length(&chptr->locmembers) == 0)
/* They're all remotes, so don't send a batch */
continue;
/* Hunt for members in the channel from the target server
* If we find one, send the channel a BATCH message */
RB_DLINK_FOREACH(ptr, chptr->members.head)
{
struct Client *client_p = ptr->data;
if(client_p->from == data)
{
rb_dlinkAddAlloc(rb_strdup(chptr->chname), clist);
sendto_channel_local_with_capability(ALL_MEMBERS, CLICAP_BATCH, NOCAPS,
chptr, ":%s BATCH +%s %s %s",
me.name,
batch == BATCH_NETSPLIT ? "netsplit" : "netjoin",
batch_p->parv[0], batch_p->parv[1]);
break;
}
}
}
}
break;
default:
s_assert(0);
break;
}
rb_dlinkAdd(batch_p, &batch_p->node, &batches[batch]);
return batch_p;
}
void
finish_batch(struct Batch *batch_p)
{
if(batch_p == NULL)
return;
/* Batch type-specific processing */
switch(batch_p->batch)
{
case BATCH_NETSPLIT:
case BATCH_NETJOIN:
{
rb_dlink_list *clist = batch_p->pdata;
rb_dlink_node *ptr, *nptr;
RB_DLINK_FOREACH_SAFE(ptr, nptr, clist->head)
{
struct Channel *chptr = find_channel(ptr->data);
if(chptr != NULL) /* Shouldn't be but just in case... */
{
sendto_channel_local_with_capability(ALL_MEMBERS, CLICAP_BATCH, NOCAPS,
chptr, ":%s BATCH -%s %s %s",
me.name,
batch_p->batch == BATCH_NETSPLIT ? "netsplit" : "netjoin",
batch_p->parv[0], batch_p->parv[1]);
}
rb_free(ptr->data);
rb_dlinkDestroy(ptr, clist);
}
rb_free(clist);
}
break;
default:
s_assert(0);
break;
}
/* Free all the strings */
for(size_t i = 0; i < (batch_p->parc - 1); i++)
rb_free(batch_p->parv[i]);
rb_free(batch_p->parv);
rb_dlinkDelete(&batch_p->node, &batches[batch_p->batch]);
rb_free(batch_p);
}
struct Batch *
find_batch(batch_type batch, void *data)
{
rb_dlink_node *ptr;
RB_DLINK_FOREACH(ptr, batches[batch].head)
{
struct Batch *batch_p = ptr->data;
if(batch_p->data == data)
return batch_p;
}
return NULL;
}

View file

@ -53,6 +53,7 @@
#include "sslproc.h" #include "sslproc.h"
#include "wsproc.h" #include "wsproc.h"
#include "s_assert.h" #include "s_assert.h"
#include "batch.h"
#define DEBUG_EXITED_CLIENTS #define DEBUG_EXITED_CLIENTS
@ -1385,14 +1386,25 @@ exit_remote_server(struct Client *client_p, struct Client *source_p, struct Clie
static char comment1[(HOSTLEN*2)+2]; static char comment1[(HOSTLEN*2)+2];
static char newcomment[BUFSIZE]; static char newcomment[BUFSIZE];
struct Client *target_p; struct Client *target_p;
struct Batch *batch_p;
if(ConfigServerHide.flatten_links) if(ConfigServerHide.flatten_links)
{
strcpy(comment1, "*.net *.split"); strcpy(comment1, "*.net *.split");
/* rb_strdup since they are later freed */
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
rb_strdup("*.net"), rb_strdup("*.split"));
}
else else
{ {
strcpy(comment1, source_p->servptr->name); strcpy(comment1, source_p->servptr->name);
strcat(comment1, " "); strcat(comment1, " ");
strcat(comment1, source_p->name); strcat(comment1, source_p->name);
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
rb_strdup(source_p->servptr->name),
rb_strdup(source_p->name));
} }
if (IsPerson(from)) if (IsPerson(from))
snprintf(newcomment, sizeof(newcomment), "by %s: %s", snprintf(newcomment, sizeof(newcomment), "by %s: %s",
@ -1430,6 +1442,7 @@ exit_remote_server(struct Client *client_p, struct Client *source_p, struct Clie
#else #else
rb_dlinkAddAlloc(source_p, &dead_list); rb_dlinkAddAlloc(source_p, &dead_list);
#endif #endif
finish_batch(batch_p);
return 0; return 0;
} }
@ -1463,6 +1476,7 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
static char comment1[(HOSTLEN*2)+2]; static char comment1[(HOSTLEN*2)+2];
static char newcomment[BUFSIZE]; static char newcomment[BUFSIZE];
unsigned int sendk, recvk; unsigned int sendk, recvk;
struct Batch *batch_p;
rb_dlinkDelete(&source_p->localClient->tnode, &serv_list); rb_dlinkDelete(&source_p->localClient->tnode, &serv_list);
rb_dlinkFindDestroy(source_p, &global_serv_list); rb_dlinkFindDestroy(source_p, &global_serv_list);
@ -1493,12 +1507,18 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
close_connection(source_p); close_connection(source_p);
if(ConfigServerHide.flatten_links) if(ConfigServerHide.flatten_links)
{
strcpy(comment1, "*.net *.split"); strcpy(comment1, "*.net *.split");
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
rb_strdup("*.net"), rb_strdup("*.split"));
}
else else
{ {
strcpy(comment1, source_p->servptr->name); strcpy(comment1, source_p->servptr->name);
strcat(comment1, " "); strcat(comment1, " ");
strcat(comment1, source_p->name); strcat(comment1, source_p->name);
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
rb_strdup(source_p->servptr->name), rb_strdup(source_p->name));
} }
if(source_p->serv != NULL) if(source_p->serv != NULL)
@ -1520,6 +1540,7 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
SetDead(source_p); SetDead(source_p);
rb_dlinkAddAlloc(source_p, &dead_list); rb_dlinkAddAlloc(source_p, &dead_list);
finish_batch(batch_p);
return 0; return 0;
} }

View file

@ -100,6 +100,7 @@ unsigned int CLICAP_USERHOST_IN_NAMES;
unsigned int CLICAP_CAP_NOTIFY; unsigned int CLICAP_CAP_NOTIFY;
unsigned int CLICAP_CHGHOST; unsigned int CLICAP_CHGHOST;
unsigned int CLICAP_ECHO_MESSAGE; unsigned int CLICAP_ECHO_MESSAGE;
unsigned int CLICAP_BATCH;
/* /*
* initialize our builtin capability table. --nenolod * initialize our builtin capability table. --nenolod
@ -147,6 +148,7 @@ init_builtin_capabs(void)
CLICAP_CAP_NOTIFY = capability_put(cli_capindex, "cap-notify", NULL); CLICAP_CAP_NOTIFY = capability_put(cli_capindex, "cap-notify", NULL);
CLICAP_CHGHOST = capability_put(cli_capindex, "chghost", NULL); CLICAP_CHGHOST = capability_put(cli_capindex, "chghost", NULL);
CLICAP_ECHO_MESSAGE = capability_put(cli_capindex, "echo-message", NULL); CLICAP_ECHO_MESSAGE = capability_put(cli_capindex, "echo-message", NULL);
CLICAP_BATCH = capability_put(cli_capindex, "batch", NULL);
} }
static CNCB serv_connect_callback; static CNCB serv_connect_callback;

View file

@ -9,6 +9,7 @@ auto_load_moddir=@moduledir@/autoload
auto_load_mod_LTLIBRARIES = \ auto_load_mod_LTLIBRARIES = \
cap_account_tag.la \ cap_account_tag.la \
cap_batch.la \
cap_server_time.la \ cap_server_time.la \
chm_nocolour.la \ chm_nocolour.la \
chm_noctcp.la \ chm_noctcp.la \

70
modules/cap_batch.c Normal file
View file

@ -0,0 +1,70 @@
/*
* charybdis: an advanced ircd.
* cap_batch.c: implement the batch IRCv3.2 capability
*
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdinc.h"
#include "modules.h"
#include "hook.h"
#include "client.h"
#include "ircd.h"
#include "send.h"
#include "s_conf.h"
#include "s_user.h"
#include "s_serv.h"
#include "numeric.h"
#include "chmode.h"
#include "batch.h"
#include "inline/stringops.h"
static const char cap_batch_desc[] =
"Provides the batch client capability";
static void cap_batch_process(hook_data *);
mapi_hfn_list_av1 cap_batch_hfnlist[] = {
{ "outbound_msgbuf", (hookfn) cap_batch_process },
{ NULL, NULL }
};
static void
cap_batch_process(hook_data *data)
{
struct MsgBuf *msgbuf = data->arg1;
struct Client *client_p = data->client;
struct Batch *batch_p;
if(rb_strcasecmp(msgbuf->cmd, "quit") == 0)
{
if(!IsClient(client_p) || MyConnect(client_p))
/* Remote users only please */
return;
/* Now find our batch... */
if((batch_p = find_batch(BATCH_NETSPLIT, client_p->from)) == NULL)
return;
/* Boom */
msgbuf_append_tag(msgbuf, "batch", batch_p->id, CLICAP_BATCH);
}
}
DECLARE_MODULE_AV2(cap_batch, NULL, NULL, NULL, NULL, cap_batch_hfnlist, NULL, NULL, cap_batch_desc);