The LoadPersistent*()/SavePersistent*() functions caused moddata to be
tagged with ->unloaded=1. Though it seems it caused no real issues this
is not good... we now properly tag them as 0 and the like. Also did a
code cleanup / overhaul on that system as well.
For other ModData we now handle the case where a module is loaded with
with a newer version and that newer version is no longer having certain
moddata, eg the name changed or it no longer needs it.
KNOWN ISSUE:
Unfortunately we cannot call the free function for the old moddata that
is no longer being handled by the newer version of the module, since the
module is already unloaded. So this will result in a memory leak, but
not in a crash.
KNOWN ISSUE:
Similarly, for SavePersistentPointer() there is a free function, again
this is called just fine if the module is permanently unloaded but NOT
if the module is reloaded with the same name and no longer is interested
in the persistent pointer object. Again, here too, that would result
in a memory leak but not in a crash.
Fortunately the "known issues" are rare. Fixing these is impossible
with the current module API because modules are unloaded after MOD_TEST
and before MOD_INIT, and only after MOD_INIT we know which moddata
is handled by the new version of the module. To change that we would
need to keep the old module around until after MOD_INIT of the new
module (so we can call free functions in the old module), but that
means delaying the MOD_UNLOAD for the old modules until after MOD_INIT
of the new modules, which changes the sequence too much that i don't
dare to do that. For example, it would mean a database save routine
in the old module would only be called after MOD_INIT finished in the
new module, which may be unexpected since right now MOD_UNLOAD is
called before MOD_INIT and maybe the db loading is done in MOD_INIT,
which would need to be moved to MOD_LOAD. That's just one example,
there may be others. I think such a change can only be done on a major
UnrealIRCd version change, so we will have to live this for now.
As said, fortunately it is a corner case.
This makes websocket_common unload last (and near-last: rpc & websocket)
and makes us call Mod_Init for these three modules first.
This way, the period where the websocket handler is unavailable is kept
to a minimum.
This also renames the ModuleSetOptions option MOD_OPT_UNLOAD_PRIORITY
to MOD_OPT_PRIORITY since it dynamically changes the module priority
in the list. For 6.x compatibility, MOD_OPT_UNLOAD_PRIORITY can still
be used.
Previously we did show a warning but we could crash a millisecond
later so that wasn't particularly helpful.
Now, is_module_loaded() can be used from HOOKTYPE_CONFIGPOSTTEST
to detect if a module is loaded or not, contrary to us having to
do it in MOD_LOAD when it is too late. So now the requirement is
really enforced and also works for hot-loading as well as
unloading of required modules is now prevented.
not a format string (eg ":%s LUSERS %s"). It now simply concats all parv[]'s.
That is, up to parc count. And it automatically does the :stuff for the
last parameter if it contains spaces or starts with a : etc.
This gets rid of a bit sketchy code with an arbitrary maximum etc.
Now it's just:
if (hunt_server(client, NULL, "REHASH", 1, parc, parv) != HUNTED_ISME)
return;
This has one side effect, though:
Previously we used the format string, so it may be possible for S2S
traffic to now have more arguments then before here and there.
Eg:
* It could be that the caller was using a format string to
intentionally cut off an extra parameter at the end.
You can still do that if you call with eg parc-1 instead of parc.
I don't think there were any such cases though, but hard to rule out.
* Extranous parameters may show up in S2S traffic where it was
previously unexpected.
It means you can no longer modify eg parv[1] in-place with strtoken and such.
The main reason for this is that as a command handler you have no idea
where the arguments may come from. It could be from a do_cmd() with
read-only storage (eg a string literal) and so on.
It started with an experiment of how far I could get and how annoying the
side-effects would be, but they seem to be quite managable, so I'm
committing this stuff.
Hopefully this catches/solves some stupid bugs somewhere :)
so modules can indicate if they wish to be unloaded before or after others.
This is used by the channel and history modules so they can save their
databases before the chanmodes modules are unloaded.
Also, made ModuleSetOptions() a void function. I don't think anyone
used the returned value and it now no longer is strictly bitmask add/del
so returning an unsigned int would be a tad confusing.
just like hooks now. Yeah we've messed up a few times by now.
Seems only Gottem uses them :D
So now it would call for example: prio -10, prio 0, 10, 20, cmd.
This matches the behavior of hook priorities (and swhois etc.)
This so I - and others - don't constantly have to wonder whether the client
is called sptr, cptr or acptr in a simple routine.
Insane --> 212 files changed, 6814 insertions(+), 6945 deletions(-)
Couldn't just mass-replace of course since there are places where there
are multiple clients involved. So had to check each function.
Also renamed some 'acptr' to 'target' and such.
I will write a page with new style rules later.. but in short if there is
only 1 client involved it will now be called 'client'.
code changes in UnrealIRCd itself:
1) Clients are no longer freed directly by exit_client. Most fields
are freed, but 'sptr' itself is not, so you can use IsDead() on it.
2) exit_client now returns void rather than int
3) ALL command functions return void rather than int.
Of course this also affects do_cmd, command overrides, etc.
This is a direct consequence of the removal of 'cptr' earlier, as that
was used to signal certain things that are now no longer possible
(and it raises the question if things were always correctly signaled
in the first place, so may fix some bugs).
It also makes the code more resillient against cases where you forgot
to check if the client was freed. Still, you are encouraged to do an
IsDead(sptr) if you are calling functions that may kill clients,
such as command functions or things that may use spamfilter.
More changes will follow, such as the removal of FLUSH_BUFFER.
'sptr' is sufficient and in most cases the only one you should care about.
Should you need it, you can access sptr->direction in cases where you
need the old information (usually only for some sendto_* functions
and some protoctl checks), so 'cptr' was redundant too.
[!] This change likely introduces some bugs. This was many hours of work.
I only cut some corners in 4 functions, which will be fixed at a later
stage..... yes, more major changes to come.
On the plus side, I likely fixed some bugs in the process. Situations
where cptr vs sptr usage was incorrect. Eg using cptr->name (near server)
when sptr->name should be used (the actual source server), etc....
which specifies the time in milliseconds rather than seconds. This
allows for additional precision, or at least multiple calls per second.
The minimum allowed every_msec value is 100 at this time.
The prototype is now: EventAdd(Module *module, char *name,
vFP event, void *data, long every_msec, int count);
crashes (has a core file) to the crash bug report.
Also, disable leak detection since this is too noisy and would cause
a core dump each time + bothering the user to submit a crash report
+ send this crashreport etc. We still enable this in our own tests
though, but not for end-users.