unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

api-event.c (5877B)

      1 /************************************************************************
      2  *   IRC - Internet Relay Chat, api-event.c
      3  *   (C) 2001- Carsten Munk (Techie/Stskeeps) <stskeeps@tspre.org>
      4  *   and the UnrealIRCd team
      5  *
      6  *   See file AUTHORS in IRC package for additional names of
      7  *   the programmers. 
      8  *
      9  *   This program is free software; you can redistribute it and/or modify
     10  *   it under the terms of the GNU General Public License as published by
     11  *   the Free Software Foundation; either version 1, or (at your option)
     12  *   any later version.
     13  *
     14  *   This program is distributed in the hope that it will be useful,
     15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *   GNU General Public License for more details.
     18  *
     19  *   You should have received a copy of the GNU General Public License
     20  *   along with this program; if not, write to the Free Software
     21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     22  */
     23 
     24 #include "unrealircd.h"
     25 
     26 ID_Copyright("(C) Carsten Munk 2001");
     27 
     28 MODVAR Event *events = NULL;
     29 
     30 /** Add an event, a function that will run at regular intervals.
     31  * @param module	Module that this event belongs to
     32  * @param name		Name of the event
     33  * @param event		The EVENT(function) to be called
     34  * @param data		The data to be passed to the function (or just NULL)
     35  * @param every_msec	Every <this> milliseconds the event will be called, but see notes.
     36  * @param count		After how many times we should stop calling this even (0 = infinite times)
     37  * @returns an Event struct
     38  * @note  UnrealIRCd will try to call the event every 'every_msec' milliseconds.
     39  *        However, in case of low traffic the minimum time is at least SOCKETLOOP_MAX_DELAY
     40  *        which is 250ms at the time of writing. Also, we reject any value below 100 msecs.
     41  *        The actual calling time will not be quicker than the specified every_msec but
     42  *        can be later, in case of high load, in very extreme cases even up to 1000 or 2000
     43  *        msec later but that would be very unusual. Just saying, it's not a guarantee..
     44  */
     45 Event *EventAdd(Module *module, const char *name, vFP event, void *data, long every_msec, int count)
     46 {
     47 	Event *newevent;
     48 
     49 	if (!name || (every_msec < 0) || (count < 0) || !event)
     50 	{
     51 		if (module)
     52 			module->errorcode = MODERR_INVALID;
     53 		return NULL;
     54 	}
     55 
     56 	newevent = safe_alloc(sizeof(Event));
     57 	safe_strdup(newevent->name, name);
     58 	newevent->count = count;
     59 	newevent->every_msec = every_msec;
     60 	newevent->event = event;
     61 	newevent->data = data;
     62 	newevent->last_run.tv_sec = timeofday_tv.tv_sec;
     63 	newevent->last_run.tv_usec = timeofday_tv.tv_usec;
     64 	newevent->owner = module;
     65 	AddListItem(newevent,events);
     66 	if (module)
     67 	{
     68 		ModuleObject *eventobj = safe_alloc(sizeof(ModuleObject));
     69 		eventobj->object.event = newevent;
     70 		eventobj->type = MOBJ_EVENT;
     71 		AddListItem(eventobj, module->objects);
     72 		module->errorcode = MODERR_NOERROR;
     73 	}
     74 	return newevent;
     75 	
     76 }
     77 
     78 /** Mark the Event for deletion.
     79  * The actual deletion of the event happens later on
     80  * (which is of no concern to the caller).
     81  */
     82 void EventDel(Event *e)
     83 {
     84 	char buf[128];
     85 
     86 	/* Mark for deletion */
     87 	e->deleted = 1;
     88 
     89 	/* Replace the name so deleted events are clearly labeled */
     90 	if (e->name)
     91 	{
     92 		snprintf(buf, sizeof(buf), "deleted:%s", e->name);
     93 		safe_strdup(e->name, buf);
     94 	}
     95 
     96 	/* Remove the event from the module, that is something we can safely do straight away */
     97 	if (e->owner)
     98 	{
     99 		ModuleObject *eventobjs;
    100 		for (eventobjs = e->owner->objects; eventobjs; eventobjs = eventobjs->next)
    101 		{
    102 			if (eventobjs->type == MOBJ_EVENT && eventobjs->object.event == e)
    103 			{
    104 				DelListItem(eventobjs, e->owner->objects);
    105 				safe_free(eventobjs);
    106 				break;
    107 			}
    108 		}
    109 		e->owner = NULL;
    110 	}
    111 }
    112 
    113 /** Remove the event for real, used only via CleanupEvents(), not for end-users. */
    114 static void EventDelReal(Event *e)
    115 {
    116 	if (!e->deleted)
    117 	{
    118 		unreal_log(ULOG_FATAL, "module", "BUG_EVENTDELREAL_ZERO", NULL,
    119 		           "[BUG] EventDelReal called while e->deleted is 0. This cannot happen. Event name: $event_name",
    120 		           log_data_string("event_name", e->name));
    121 		abort();
    122 	}
    123 	if (e->owner)
    124 	{
    125 		unreal_log(ULOG_FATAL, "module", "BUG_EVENTDELREAL_NULL", NULL,
    126 		           "[BUG] EventDelReal called while e->owner is NULL. This cannot happen. Event name: $event_name",
    127 		           log_data_string("event_name", e->name));
    128 		abort();
    129 	}
    130 	safe_free(e->name);
    131 	DelListItem(e, events);
    132 	safe_free(e);
    133 }
    134 
    135 /** Remove any events that were previously marked for deletion */
    136 static void CleanupEvents(void)
    137 {
    138 	Event *e, *e_next;
    139 	for (e = events; e; e = e_next)
    140 	{
    141 		e_next = e->next;
    142 		if (e->deleted)
    143 			EventDelReal(e);
    144 	}
    145 }
    146 
    147 Event *EventFind(const char *name)
    148 {
    149 	Event *eventptr;
    150 
    151 	for (eventptr = events; eventptr; eventptr = eventptr->next)
    152 		if (!strcmp(eventptr->name, name))
    153 			return (eventptr);
    154 	return NULL;
    155 }
    156 
    157 int EventMod(Event *event, EventInfo *mods)
    158 {
    159 	if (!event || !mods)
    160 	{
    161 		if (event && event->owner)
    162 			event->owner->errorcode = MODERR_INVALID;
    163 		return -1;
    164 	}
    165 
    166 	if (mods->flags & EMOD_EVERY)
    167 		event->every_msec = mods->every_msec;
    168 	if (mods->flags & EMOD_HOWMANY)
    169 		event->count = mods->count;
    170 	if (mods->flags & EMOD_NAME)
    171 		safe_strdup(event->name, mods->name);
    172 	if (mods->flags & EMOD_EVENT)
    173 		event->event = mods->event;
    174 	if (mods->flags & EMOD_DATA)
    175 		event->data = mods->data;
    176 	if (event->owner)
    177 		event->owner->errorcode = MODERR_NOERROR;
    178 	return 0;
    179 }
    180 
    181 void DoEvents(void)
    182 {
    183 	Event *e;
    184 
    185 	for (e = events; e; e = e->next)
    186 	{
    187 		if (e->deleted)
    188 			continue;
    189 		if (e->count == -1)
    190 		{
    191 			EventDel(e);
    192 			continue;
    193 		}
    194 		if ((e->every_msec == 0) || minimum_msec_since_last_run(&e->last_run, e->every_msec))
    195 		{
    196 			(*e->event)(e->data);
    197 			if (e->count > 0)
    198 			{
    199 				e->count--;
    200 				if (e->count == 0)
    201 				{
    202 					EventDel(e);
    203 					continue;
    204 				}
    205 			}
    206 		}
    207 	}
    208 
    209 	CleanupEvents();
    210 }