New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MODESYNC #63

Closed
cooper opened this Issue Jun 29, 2016 · 6 comments

Comments

Projects
None yet
1 participant
@cooper
Owner

cooper commented Jun 29, 2016

Purpose of MODESYNC

MODESYNC allows servers to synchronize modes set on channels. Because mode handling functionality is provided by modules, the IRCd cannot queue modes for modules that might be loaded in the future. MODESYNC solves this problem by providing a means of negotiation when new channel modes are dynamically introduced to a server.

How unknown modes are currently dealt with

Modes unknown to the local server should not cause issues in JELP. Even if the local server does not recognize incoming modes and cannot act upon them, it at least knows the mode type, which is enough to determine the behavior of its parameters. However, the parameters for unknown modes are not stored because some require processing which the server could not possibly do without the associated module.

What MODESYNC would change

A server with MODESYNC enabled would behave the same as described above. For as long as a mode is unknown, its parameters will not be stored, and mode changes will not be queued. Rather than implementing a mode queue, MODESYNC provides a means by which servers can request modes and their parameters once they become available.

Technical details

This is the specification for MODESYNC support in the JELP protocol.

MODEREQ

:<SID> MODEREQ <channel>|* <target SID>|* <modes>|*

A MODESYNC request.

Usually sent by a server to all uplinks when a new mode is introduced, such as by a module. The modes are always sent in the perspective of the source server represented by <SID>.

If the target server represented by <target SID> is the receiving server, the receiving server MUST reply with the MODESYNC REP command, documented below.

If <target SID> is an asterisk (*), the receiving server MUST reply with the MODESYNC REP command, documented below, and the message MUST then be forwarded to all uplinks besides the origin.

If <target SID> is a server other than the receiving server, the message MUST be forwarded to the physical location of that server.

When replying to a MODEREQ with a MODEREP, the <target SID> should be that of the MODEREQ command's source server. However, if the request's modes parameter is an asterisk (*), this indicates a network-wide MODESYNC of all modes in a particular channel, so the REP should be sent with an asterisk (*) as the <target SID> as well.

Parameters

  • channel - the channel for which replies are expected. an asterisk (*) is permitted for all channels affected by the mode.
  • target SID - the server from which replies are expected. an asterisk (*) is permitted for all servers implementing MODESYNC.
  • modes - an unsigned string of modes being requested.

MODEREP

:<SID> MODEREP <channel> <target SID>|* :<mode string>

A MODESYNC reply.

If the target server represented by <target SID> is the receiving server, the receiving server MUST handle the mode string from the perspective of the source server represented by <SID>.

If <target SID> is an asterisk (*), the receiving server MUST handle the mode string from the perspective of the source server represented by <SID>, and the message MUST then be forwarded to all uplinks besides the origin.

If <target SID> is a server other than the receiving server, the message MUST be forwarded to the physical location of that server.

To prevent flooding users with MODE messages, modes which are already set or whose parameters are unchanged MUST be ignored.

Parameters

  • channel - the channel associated with this mode string.
  • target SID - the server which initiated the request. an asterisk (*) is permitted for all servers implementing MODESYNC.
  • mode string - the mode string, including all possible parameters.

Example

This is an example scenario where a server administrator loads a module providing a new channel mode.

Adding a mode definition to the configuration

The IRC operator of the server k.notroll.net with SID 0 adds the access mode to ircd.conf with the letter A and mode type 3. He rehashes the configuration. The server sends an ACM (add channel mode) message for adding or deleting any mode definitions which have changed.

:0 ACM access:A:3

Loading the module providing the mode

The IRC operator of the server k.notroll.net with SID 0 loads the Access module, providing the channel mode access which this server knows by the letter A. The server sends a MODEREQ command with channel target * to indicate that information for all affected channels is being requested and server target * to indicate that all servers implementing MODESYNC should reply.

:0 MODEREQ * * A

Each server implementing MODESYNC will reply with a separate MODESYNC REP for each affected channel. The reply, like the request, can include multiple modes. In this example, only one mode is used.

:1 MODEREP #a 0 :+AA op:*!*@example.com owner:*!*@example.com
:1 MODEREP #b 0 :+A op:*!*@example.com
:2 MODEREP #a 0 :+AA op:*!*@example.com owner:*!*@example.com
:2 MODEREP #b 0 :+A op:*!*@example.com

TODO

  • Make AUM and ACM accept a minus sign (-) in front of any mode name to indicate that it should be disabled. Only send if they are being deleted or introduced or the letter or type has changed
  • Send out AUM and ACM dynamically as new modes are introduced or disabled
  • Add channel method to generate mode strings that include ONLY the specifically requested modes.
  • Implement MODEREQ command
  • Implement MODEREP command
  • Implement MODESYNC user command

@cooper cooper added this to the v12 milestone Jun 29, 2016

@cooper cooper modified the milestones: v13, v12 Jul 22, 2016

cooper added a commit that referenced this issue Sep 22, 2016

cooper added a commit that referenced this issue Sep 22, 2016

cooper added a commit that referenced this issue Sep 22, 2016

12.06: added utilities mode_change_start() and mode_change_end(). AUM…
… and ACM are now sent out dynamically when new modes are added and removed. #63.             AUM and ACM for juno servers now only advertise modes which are actually available for use.
@cooper

This comment has been minimized.

Owner

cooper commented Sep 22, 2016

AUM and ACM work differently than in the past. Since they are now used to indicate remote availability of modes, they are more strict. In the initial burst, only modes which have blocks are sent out. It used to send out all modes that had a letter mapped to them (all supported modes in default.conf usually). Now it only sends out the ones with code to support them. AUM and ACM are sent out upon MODLOAD, MODUNLOAD, MODRELOAD, and RELOAD commands as necessary.

@cooper

This comment has been minimized.

Owner

cooper commented Sep 22, 2016

For a moment I was thinking that I'd made a mistake by making the above change to AUM and ACM, but I think a minor adjustment will fix it.

Even if the local server does not recognize incoming modes and cannot act upon them, it at least knows the mode type, which is enough to determine the behavior of its parameters.

There is a problem with this, yes. Let's say you have a channel with some mute bans, then you unload Channel::Mute. Currently, the modes remain. They will continue to be propagated over S2S (and ignored by servers that do not recognize them). This is a problem because unregistered modes could then appear in strings.

I think InspIRCd locally unsets all the modes provided by a module when you unload it. I think. Assuming I decide to do the same, I should stress that they should only be unset locally. This MODESYNC spec would reintroduce the modes from remote servers if the module is loaded again on the local server.

cooper added a commit that referenced this issue Sep 23, 2016

@cooper

This comment has been minimized.

Owner

cooper commented Sep 23, 2016

Ran into another problem with the unsetting of modes mentioned above. The code I added to detect when modes become unavailable is only capable of recognizing that AFTER a module providing modes is unloaded. At that point, the code for unsetting the modes is no longer present. So I guess I need something to tell MODESYNC that modes will SOON become unavailable.

@cooper

This comment has been minimized.

Owner

cooper commented Sep 23, 2016

Follow-up on that: I did a sort of lazy thing. The mode block is moved to a temporary location in the pool. The ->do_modes() method is called with a special argument which tells it to look in this temporary location instead of the default location. It works fine; the only thing I can think of where it might cause an issue is if a mode block depends on a subroutine in a given module's symbol table. That would fail because the module will have been unloaded and the symbol table cleared by the time the mode block is called. That in mind, I wrapped this temporary mode block call in an eval. But mode blocks don't usually depend on external subroutines anyway. So we should be good.

cooper added a commit that referenced this issue Dec 6, 2016

@cooper

This comment has been minimized.

Owner

cooper commented Dec 6, 2016

Split up into two commands: MODEREQ (the request, formerly MODESYNC REQ) and MODEREP (the reply, formerly MODESYNC REP).

cooper added a commit that referenced this issue Dec 11, 2016

cooper added a commit that referenced this issue Dec 11, 2016

@cooper

This comment has been minimized.

Owner

cooper commented Dec 11, 2016

MODESYNC is done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment