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:
parent
4f2b9a4fd1
commit
2373891299
8 changed files with 346 additions and 1 deletions
47
include/batch.h
Normal file
47
include/batch.h
Normal 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);
|
|
@ -68,6 +68,7 @@ extern unsigned int CLICAP_USERHOST_IN_NAMES;
|
|||
extern unsigned int CLICAP_CAP_NOTIFY;
|
||||
extern unsigned int CLICAP_CHGHOST;
|
||||
extern unsigned int CLICAP_ECHO_MESSAGE;
|
||||
extern unsigned int CLICAP_BATCH;
|
||||
|
||||
/*
|
||||
* XXX: this is kind of ugly, but this allows us to have backwards
|
||||
|
|
|
@ -21,6 +21,7 @@ endif
|
|||
libircd_la_SOURCES = \
|
||||
authproc.c \
|
||||
bandbi.c \
|
||||
batch.c \
|
||||
cache.c \
|
||||
capability.c \
|
||||
channel.c \
|
||||
|
|
202
ircd/batch.c
Normal file
202
ircd/batch.c
Normal 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;
|
||||
}
|
|
@ -53,6 +53,7 @@
|
|||
#include "sslproc.h"
|
||||
#include "wsproc.h"
|
||||
#include "s_assert.h"
|
||||
#include "batch.h"
|
||||
|
||||
#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 newcomment[BUFSIZE];
|
||||
struct Client *target_p;
|
||||
struct Batch *batch_p;
|
||||
|
||||
if(ConfigServerHide.flatten_links)
|
||||
{
|
||||
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
|
||||
{
|
||||
strcpy(comment1, source_p->servptr->name);
|
||||
strcat(comment1, " ");
|
||||
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))
|
||||
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
|
||||
rb_dlinkAddAlloc(source_p, &dead_list);
|
||||
#endif
|
||||
finish_batch(batch_p);
|
||||
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 newcomment[BUFSIZE];
|
||||
unsigned int sendk, recvk;
|
||||
struct Batch *batch_p;
|
||||
|
||||
rb_dlinkDelete(&source_p->localClient->tnode, &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);
|
||||
|
||||
if(ConfigServerHide.flatten_links)
|
||||
{
|
||||
strcpy(comment1, "*.net *.split");
|
||||
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
|
||||
rb_strdup("*.net"), rb_strdup("*.split"));
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(comment1, source_p->servptr->name);
|
||||
strcat(comment1, " ");
|
||||
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)
|
||||
|
@ -1520,6 +1540,7 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
|
|||
|
||||
SetDead(source_p);
|
||||
rb_dlinkAddAlloc(source_p, &dead_list);
|
||||
finish_batch(batch_p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ unsigned int CLICAP_USERHOST_IN_NAMES;
|
|||
unsigned int CLICAP_CAP_NOTIFY;
|
||||
unsigned int CLICAP_CHGHOST;
|
||||
unsigned int CLICAP_ECHO_MESSAGE;
|
||||
unsigned int CLICAP_BATCH;
|
||||
|
||||
/*
|
||||
* 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_CHGHOST = capability_put(cli_capindex, "chghost", NULL);
|
||||
CLICAP_ECHO_MESSAGE = capability_put(cli_capindex, "echo-message", NULL);
|
||||
CLICAP_BATCH = capability_put(cli_capindex, "batch", NULL);
|
||||
}
|
||||
|
||||
static CNCB serv_connect_callback;
|
||||
|
|
|
@ -9,6 +9,7 @@ auto_load_moddir=@moduledir@/autoload
|
|||
|
||||
auto_load_mod_LTLIBRARIES = \
|
||||
cap_account_tag.la \
|
||||
cap_batch.la \
|
||||
cap_server_time.la \
|
||||
chm_nocolour.la \
|
||||
chm_noctcp.la \
|
||||
|
|
70
modules/cap_batch.c
Normal file
70
modules/cap_batch.c
Normal 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);
|
Loading…
Reference in a new issue