From 1b8501f2dc84cd83ae9ad7464c57fe012ab4eada Mon Sep 17 00:00:00 2001 From: Perry Lorier Date: Fri, 8 Mar 2002 23:19:33 +0000 Subject: [PATCH] Author: Carlo Wood Log message: Implementation of network synchronization code. Includes the implementation of the previously unused DESTRUCT message. Correction on ms_join to copy older timestamps and now allowing BURST message to occur outside the net-burst. See my last two posts to coder-com for detailed information on how I got to this implementation and for a C++ simulation program that wrote to test it. Note that I changed the copyright notice in m_destruct - Jarko didn't add that function, I did. Not that it is a big deal to me. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@668 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 15 +++++- include/channel.h | 2 + ircd/m_burst.c | 39 ++++++++++---- ircd/m_destruct.c | 130 +++++++++++++++++++++++----------------------- ircd/m_join.c | 5 ++ ircd/m_part.c | 18 +++---- 6 files changed, 122 insertions(+), 87 deletions(-) diff --git a/ChangeLog b/ChangeLog index 65e4ebe..d3b33e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ -2002-02-27 Reed Loden +2002-03-08 Carlo Wood + * include/channel.h: Added CHFL_BURST_ALREADY_OPPED + and CHFL_BURST_ALREADY_VOICED. + + * ircd/m_burst.c: Allow BURST outside net-burst + and take into account that users are already joined + to the channel in that case. + * ircd/m_destruct.c: Implementation of DESTRUCT + handling code. + + * ircd/m_join.c: Set the channel creationtime to + the timestamp of a message when that timestamp is + smaller. +2002-02-27 Reed Loden * tools/crypter: Updated some variables, added another notice, added CVS Id tag, and updated Perl location. diff --git a/include/channel.h b/include/channel.h index 2825da7..131e11d 100644 --- a/include/channel.h +++ b/include/channel.h @@ -67,6 +67,8 @@ struct Client; #define CHFL_BANVALID 0x0800 /* CHFL_BANNED bit is valid */ #define CHFL_BANNED 0x1000 /* Channel member is banned */ #define CHFL_SILENCE_IPMASK 0x2000 /* silence mask is an IP-number mask */ +#define CHFL_BURST_ALREADY_OPPED 0x04000 /* In oob BURST, but was already joined and opped */ +#define CHFL_BURST_ALREADY_VOICED 0x08000 /* In oob BURST, but was already joined and voiced */ #define CHFL_OVERLAP (CHFL_CHANOP | CHFL_VOICE) #define CHFL_BANVALIDMASK (CHFL_BANVALID | CHFL_BANNED) diff --git a/ircd/m_burst.c b/ircd/m_burst.c index 0f1e8bf..e253acb 100644 --- a/ircd/m_burst.c +++ b/ircd/m_burst.c @@ -167,6 +167,11 @@ * the TS in the BURST message, then we cancel all existing modes. * If its is smaller then the received BURST message is ignored. * If it's equal, then the received modes are just added. + * + * BURST is also accepted outside a netburst now because it + * is sent upstream as reaction to a DESTRUCT message. For + * these BURST messages it is possible that the listed channel + * members are already joined. */ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { @@ -182,10 +187,6 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) if (parc < 3) return protocol_violation(sptr,"Too few parameters for BURST"); - if (!IsBurst(sptr)) /* don't allow BURST outside of burst */ - return exit_client_msg(cptr, cptr, &me, "HACK: BURST message outside " - "net.burst from %s", cli_name(sptr)); - if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE))) return 0; /* can't create the channel? */ @@ -193,7 +194,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) /* turn off burst joined flag */ for (member = chptr->members; member; member = member->next_member) - member->status &= ~CHFL_BURST_JOINED; + member->status &= ~(CHFL_BURST_JOINED|CHFL_BURST_ALREADY_OPPED|CHFL_BURST_ALREADY_VOICED); if (!chptr->creationtime) /* mark channel as created during BURST */ chptr->mode.mode |= MODE_BURSTADDED; @@ -304,6 +305,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) int last_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; int oplevel = -1; /* Mark first field with digits: means the same as 'o' (but with level). */ int last_oplevel = 0; + struct Membership* member; for (nick = ircd_strtok(&p, nicklist, ","); nick; nick = ircd_strtok(&p, 0, ",")) { @@ -381,14 +383,29 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) last_oplevel = oplevel; } - add_user_to_channel(chptr, acptr, current_mode, oplevel); - sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, "%H", chptr); + if (IsBurst(sptr) || !(member = find_member_link(chptr, acptr))) + { + add_user_to_channel(chptr, acptr, current_mode, oplevel); + sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, "%H", chptr); + } + else + { + /* The member was already joined (either by CREATE or JOIN). + Remember the current mode. */ + if (member->status & CHFL_CHANOP) + member->status |= CHFL_BURST_ALREADY_OPPED; + if (member->status & CHFL_VOICE) + member->status |= CHFL_BURST_ALREADY_VOICED; + /* Synchronize with the burst. */ + member->status |= CHFL_BURST_JOINED | (current_mode & (CHFL_CHANOP|CHFL_VOICE)); + member->oplevel = oplevel; + } } } param++; break; - } /* switch (*parv[param]) { */ - } /* while (param < parc) { */ + } /* switch (*parv[param]) */ + } /* while (param < parc) */ nickstr[nickpos] = '\0'; banstr[banpos] = '\0'; @@ -409,9 +426,9 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) /* first deal with channel members */ for (member = chptr->members; member; member = member->next_member) { if (member->status & CHFL_BURST_JOINED) { /* joined during burst */ - if (member->status & CHFL_CHANOP) + if ((member->status & CHFL_CHANOP) && !(member->status & CHFL_BURST_ALREADY_OPPED)) modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user); - if (member->status & CHFL_VOICE) + if ((member->status & CHFL_VOICE) && !(member->status & CHFL_BURST_ALREADY_VOICED)) modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user); } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */ if (member->status & CHFL_CHANOP) diff --git a/ircd/m_destruct.c b/ircd/m_destruct.c index fc4e77d..a81c6d8 100644 --- a/ircd/m_destruct.c +++ b/ircd/m_destruct.c @@ -1,7 +1,6 @@ /* * IRC - Internet Relay Chat, ircd/m_destruct.c - * Copyright (C) 1990 Jarkko Oikarinen and - * University of Oulu, Computing Center + * Copyright (C) 1997 Carlo Wood. * * See file AUTHORS in IRC package for additional names of * the programmers. @@ -23,62 +22,6 @@ * $Id$ */ -/* - * m_functions execute protocol messages on this server: - * - * cptr is always NON-NULL, pointing to a *LOCAL* client - * structure (with an open socket connected!). This - * identifies the physical socket where the message - * originated (or which caused the m_function to be - * executed--some m_functions may call others...). - * - * sptr is the source of the message, defined by the - * prefix part of the message if present. If not - * or prefix not found, then sptr==cptr. - * - * (!IsServer(cptr)) => (cptr == sptr), because - * prefixes are taken *only* from servers... - * - * (IsServer(cptr)) - * (sptr == cptr) => the message didn't - * have the prefix. - * - * (sptr != cptr && IsServer(sptr) means - * the prefix specified servername. (?) - * - * (sptr != cptr && !IsServer(sptr) means - * that message originated from a remote - * user (not local). - * - * combining - * - * (!IsServer(sptr)) means that, sptr can safely - * taken as defining the target structure of the - * message in this server. - * - * *Always* true (if 'parse' and others are working correct): - * - * 1) sptr->from == cptr (note: cptr->from == cptr) - * - * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr - * *cannot* be a local connection, unless it's - * actually cptr!). [MyConnect(x) should probably - * be defined as (x == x->from) --msa ] - * - * parc number of variable parameter strings (if zero, - * parv is allowed to be NULL) - * - * parv a NULL terminated list of parameter pointers, - * - * parv[0], sender (prefix string), if not present - * this points to an empty string. - * parv[1]...parv[parc-1] - * pointers to additional parameters - * parv[parc] == NULL, *always* - * - * note: it is guaranteed that parv[0]..parv[parc-1] are all - * non-NULL pointers. - */ #include "config.h" #include "client.h" @@ -90,6 +33,8 @@ #include "numeric.h" #include "numnicks.h" #include "send.h" +#include "channel.h" +#include "destruct_event.h" #include #include @@ -97,17 +42,54 @@ /* * ms_destruct - server message handler * + * Added 1997 by Run, actually coded and used since 2002. + * * parv[0] = sender prefix * parv[1] = channel channelname * parv[2] = channel time stamp * - * This function does nothing, it does passes DESTRUCT to the other servers. - * In the future we will start to use this message. - * + * This message is intended to destruct _empty_ channels. + * + * The reason it is needed is to somehow add the notion + * "I destructed information" to the networks state + * (also messages that are still propagating are part + * of the global state). Without it the network could + * easily be desynced as a result of destructing a channel + * on only a part of the network while keeping the modes + * and creation time on others. + * There are three possible ways a DESTRUCT message is + * handled by remote servers: + * 1) The channel is empty and has the same timestamp + * as on the message. Conclusion: The channel has + * not been destructed and recreated in the meantime, + * this means that the normal synchronization rules + * account and we react as if we decided to destruct + * the channel ourselfs: we destruct the channel and + * send a DESTRUCT in all directions. + * 2) The channel is not empty. In case we cannot remove + * it and do not propagate the DESTRUCT message. Instead + * a resynchronizing BURST message is sent upstream + * in order to restore the channel on that side (which + * will have a TS younger than the current channel if + * it was recreated and will thus be fully synced, just + * like in the case of a real net-junction). + * 3) The channel is empty, but the creation time of the + * channel is older than the timestamp on the message. + * This can happen when there is more than one minute + * lag and remotely a channel was created slightly + * after we created the channel, being abandoned again + * and staying empty for a minute without that our + * CREATE reached that remote server. The remote server + * then could have generated the DESTRUCT. In the meantime + * our user also left the channel. We can ignore the + * destruct because it comes from an 'area' that will + * be overriden by our own CREATE: the state that generated + * this DESTRUCT is 'history'. */ int ms_destruct(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { time_t chanTS; /* Creation time of the channel */ + struct Channel* chptr; assert(0 != cptr); assert(0 != sptr); @@ -116,14 +98,30 @@ int ms_destruct(struct Client* cptr, struct Client* sptr, int parc, char* parv[] if (parc < 3 || EmptyString(parv[2])) return need_more_params(sptr,"DESTRUCT"); - /* Don't pass on DESTRUCT messages for channels that exist */ - if (FindChannel(parv[1])) + chanTS = atoi(parv[2]); + + /* Ignore DESTRUCT messages for non-existing channels. */ + if (!(chptr = FindChannel(parv[1]))) return 0; - chanTS = atoi(parv[2]); + /* Ignore DESTRUCT when the channel is older than the + timestamp on the message. */ + if (chanTS > chptr->creationtime) + return 0; + + /* Don't pass on DESTRUCT messages for channels that + are not empty, but instead send a BURST msg upstream. */ + if (chptr->users > 0) { + send_channel_modes(cptr, chptr); + return 0; + } + + /* Pass on DESTRUCT message and ALSO bounce it back! */ + sendcmdto_serv_butone(sptr, CMD_DESTRUCT, 0, "%s %Tu", parv[1], chanTS); - /* Pass on DESTRUCT message */ - sendcmdto_serv_butone(sptr, CMD_DESTRUCT, cptr, "%s %Tu", parv[1], chanTS); + /* Remove the empty channel. */ + remove_destruct_event(chptr); + destruct_channel(chptr); return 0; } diff --git a/ircd/m_join.c b/ircd/m_join.c index e8f9beb..50ddfc7 100644 --- a/ircd/m_join.c +++ b/ircd/m_join.c @@ -332,6 +332,7 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) } else { /* We have a valid channel? */ if ((member = find_member_link(chptr, sptr))) { + /* It is impossible to get here --Run */ if (!IsZombie(member)) /* already on channel */ continue; @@ -340,6 +341,10 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) chptr = FindChannel(name); } else flags = CHFL_DEOPPED | ((cli_flags(sptr) & FLAGS_TS8) ? CHFL_SERVOPOK : 0); + /* Always copy the timestamp when it is older, that is the only way to + ensure network-wide synchronization of creation times. */ + if (creation && creation < chptr->creationtime) + chptr->creationtime = creation; } joinbuf_join(&join, chptr, flags); diff --git a/ircd/m_part.c b/ircd/m_part.c index 34e6b64..020b97a 100644 --- a/ircd/m_part.c +++ b/ircd/m_part.c @@ -106,6 +106,7 @@ int m_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) struct Channel *chptr; struct Membership *member; struct JoinBuf parts; + unsigned int flags = 0; char *p = 0; char *name; @@ -138,8 +139,14 @@ int m_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) assert(!IsZombie(member)); /* Local users should never zombie */ - joinbuf_join(&parts, chptr, /* part client from channel */ - member_can_send_to_channel(member) ? 0 : CHFL_BANNED); + if (!member_can_send_to_channel(member)) + { + flags |= CHFL_BANNED; + /* Remote clients don't want to see a comment either. */ + parts.jb_comment = 0; + } + + joinbuf_join(&parts, chptr, flags); /* part client from channel */ } return joinbuf_flush(&parts); /* flush channel parts */ @@ -186,13 +193,6 @@ int ms_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (IsZombie(member)) /* figure out special flags... */ flags |= CHFL_ZOMBIE; - /* - * XXX BUG: If a client /part's with a part notice, on channels where - * he's banned, local clients will not see the part notice, but remote - * clients will. - */ - if (!member_can_send_to_channel(member)) - flags |= CHFL_BANNED; /* part user from channel */ joinbuf_join(&parts, chptr, flags); -- 2.20.1