[IRC-Dev CVS] SF.net SVN: irc-dev:[198] ircd/trunk
Brought to you by:
zolty
|
From: <zo...@us...> - 2008-08-15 18:53:59
|
Revision: 198
http://irc-dev.svn.sourceforge.net/irc-dev/?rev=198&view=rev
Author: zolty
Date: 2008-08-15 18:54:05 +0000 (Fri, 15 Aug 2008)
Log Message:
-----------
Soporte de RESTART/DIE diferido
Modified Paths:
--------------
ircd/trunk/include/ircd.h
ircd/trunk/include/send.h
ircd/trunk/ircd/ddb.c
ircd/trunk/ircd/engine_devpoll.c
ircd/trunk/ircd/engine_epoll.c
ircd/trunk/ircd/engine_kqueue.c
ircd/trunk/ircd/engine_poll.c
ircd/trunk/ircd/engine_select.c
ircd/trunk/ircd/ircd.c
ircd/trunk/ircd/ircd_signal.c
ircd/trunk/ircd/m_die.c
ircd/trunk/ircd/m_restart.c
ircd/trunk/ircd/send.c
Modified: ircd/trunk/include/ircd.h
===================================================================
--- ircd/trunk/include/ircd.h 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/include/ircd.h 2008-08-15 18:54:05 UTC (rev 198)
@@ -45,6 +45,15 @@
int pid_fd; /**< File descriptor for process id file. */
};
+/** Describes pending exit. */
+struct PendingExit
+{
+ int restart; /**< Pending exit is for a restart. */
+ char* who; /**< Who initiated the exit. */
+ char* message; /**< Message to emit. */
+ time_t time; /**< Absolute time at which to exit. */
+};
+
/*
* Macros
*/
@@ -61,13 +70,21 @@
#define MAJOR_PROTOCOL "10" /**< Current protocol version. */
#define BASE_VERSION "u2.10" /**< Base name of IRC daemon version. */
+#define PEND_INT_LONG 300 /**< Length of long message interval. */
+#define PEND_INT_MEDIUM 60 /**< Length of medium message interval. */
+#define PEND_INT_SHORT 30 /**< Length of short message interval. */
+#define PEND_INT_END 10 /**< Length of the end message interval. */
+#define PEND_INT_LAST 1 /**< Length of last message interval. */
+
/*
* Proto types
*/
-extern void server_die(const char* message);
extern void server_panic(const char* message);
-extern void server_restart(const char* message);
+extern void exit_cancel(struct Client *who);
+extern void exit_schedule(int restart, time_t when, struct Client *who,
+ const char *message);
+
extern struct Client me;
extern time_t CurrentTime;
extern struct Client* GlobalClientList;
Modified: ircd/trunk/include/send.h
===================================================================
--- ircd/trunk/include/send.h 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/include/send.h 2008-08-15 18:54:05 UTC (rev 198)
@@ -139,4 +139,7 @@
unsigned int mask, time_t *rate,
const char *pattern, ...);
+/* Send server notice to all local users */
+extern void sendto_lusers(const char *pattern, ...);
+
#endif /* INCLUDED_send_h */
Modified: ircd/trunk/ircd/ddb.c
===================================================================
--- ircd/trunk/ircd/ddb.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/ddb.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -244,6 +244,7 @@
sendto_opmask(0, SNO_OLDSNO, "Lo: %d Hashtable_Lo: %d Hi: %d Hashtable_Hi %d",
lo, ddb_hashtable_lo[table], hi, ddb_hashtable_hi[table]);
+#if 0
if ((ddb_hashtable_hi[table] != hi) || (ddb_hashtable_lo[table] != lo))
{
struct DLink *lp;
@@ -266,6 +267,7 @@
}
}
else
+#endif
{
ddb_db_hash_write(table);
@@ -744,7 +746,7 @@
else if (IsServer(acptr))
sendcmdto_one(&me, CMD_ERROR, acptr, ":Terminated by %s", exitmsg);
}
- server_die(exitmsg);
+ exit_schedule(0, 0, 0, exitmsg);
}
/** Finalizes the %DDB subsystem.
Modified: ircd/trunk/ircd/engine_devpoll.c
===================================================================
--- ircd/trunk/ircd/engine_devpoll.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/engine_devpoll.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -316,7 +316,7 @@
timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
ERROR_EXPIRE_TIME);
else if (errors > DEVPOLL_ERROR_THRESHOLD) /* too many errors... */
- server_restart("too many /dev/poll errors");
+ exit_schedule(1, 0, 0, ""too many /dev/poll errors");
}
/* old code did a sleep(1) here; with usage these days,
* that may be too expensive
Modified: ircd/trunk/ircd/engine_epoll.c
===================================================================
--- ircd/trunk/ircd/engine_epoll.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/engine_epoll.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -278,7 +278,7 @@
timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
ERROR_EXPIRE_TIME);
else if (errors > EPOLL_ERROR_THRESHOLD)
- server_restart("too many epoll errors");
+ exit_schedule(1, 0, 0, "too many epoll errors");
}
continue;
}
Modified: ircd/trunk/ircd/engine_kqueue.c
===================================================================
--- ircd/trunk/ircd/engine_kqueue.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/engine_kqueue.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -345,7 +345,7 @@
timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
ERROR_EXPIRE_TIME);
else if (errors > KQUEUE_ERROR_THRESHOLD) /* too many errors... */
- server_restart("too many kevent errors");
+ exit_schedule(1, 0, 0, "too many kevent errors");
}
/* old code did a sleep(1) here; with usage these days,
* that may be too expensive
Modified: ircd/trunk/ircd/engine_poll.c
===================================================================
--- ircd/trunk/ircd/engine_poll.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/engine_poll.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -303,7 +303,7 @@
timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
ERROR_EXPIRE_TIME);
else if (errors > POLL_ERROR_THRESHOLD) /* too many errors... */
- server_restart("too many poll errors");
+ exit_schedule(1, 0, 0, "too many poll errors");
}
/* old code did a sleep(1) here; with usage these days,
* that may be too expensive
Modified: ircd/trunk/ircd/engine_select.c
===================================================================
--- ircd/trunk/ircd/engine_select.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/engine_select.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -296,7 +296,7 @@
timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
ERROR_EXPIRE_TIME);
else if (errors > SELECT_ERROR_THRESHOLD) /* too many errors... */
- server_restart("too many select errors");
+ exit_schedule(1, 0, 0, "too many select errors");
}
/* old code did a sleep(1) here; with usage these days,
* that may be too expensive
Modified: ircd/trunk/ircd/ircd.c
===================================================================
--- ircd/trunk/ircd/ircd.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/ircd.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -40,6 +40,7 @@
#include "ircd_log.h"
#include "ircd_reply.h"
#include "ircd_signal.h"
+#include "ircd_snprintf.h"
#include "ircd_string.h"
#include "jupe.h"
#include "list.h"
@@ -121,6 +122,7 @@
static struct Timer connect_timer; /**< timer structure for try_connections() */
static struct Timer ping_timer; /**< timer structure for check_pings() */
static struct Timer destruct_event_timer; /**< timer structure for exec_expired_destruct_events() */
+static struct Timer countdown_timer; /**< timer structure for exit_countdown() */
/** Daemon information. */
static struct Daemon thisServer = { 0, 0, 0, 0, 0, 0, -1 };
@@ -129,83 +131,290 @@
int running = 1;
-/*----------------------------------------------------------------------------
- * API: server_die
- *--------------------------------------------------------------------------*/
-/** Terminate the server with a message.
- * @param[in] message Message to log and send to operators.
+/**
+ * Perform a restart or die, sending and logging all necessary messages.
+ * @param[in] pe Pointer to structure describing pending exit.
*/
-void server_die(const char *message)
+static void pending_exit(struct PendingExit *pe)
{
- /* log_write will send out message to both log file and as server notice */
- log_write(LS_SYSTEM, L_CRIT, 0, "Server terminating: %s", message);
+ static int looping = 0;
+ enum LogLevel level = pe->restart ? L_WARNING : L_CRIT;
+ const char *what = pe->restart ? "restarting" : "terminating";
+
+ if (looping++) /* increment looping to prevent looping */
+ return;
+
+ if (pe->message) {
+ sendto_lusers("Server %s: %s", what, pe->message);
+
+ if (pe->who) { /* write notice to log */
+ log_write(LS_SYSTEM, level, 0, "%s %s server: %s", pe->who, what,
+ pe->message);
+ sendcmdto_serv(&me, CMD_SQUIT, 0, "%s 0 :%s %s server: %s",
+ cli_name(&me), pe->who, what, pe->message);
+ } else {
+ log_write(LS_SYSTEM, level, 0, "Server %s: %s", what, pe->message);
+ sendcmdto_serv(&me, CMD_SQUIT, 0, "%s 0 :Server %s: %s",
+ cli_name(&me), what, pe->message);
+ }
+ } else { /* just notify of the restart/termination */
+ sendto_lusers("Server %s...", what);
+
+ if (pe->who) { /* write notice to log */
+ log_write(LS_SYSTEM, level, 0, "%s %s server...", pe->who, what);
+ sendcmdto_serv(&me, CMD_SQUIT, 0, "%s 0 :%s %s server...",
+ cli_name(&me), pe->who, what);
+ } else {
+ log_write(LS_SYSTEM, level, 0, "Server %s...", what);
+ sendcmdto_serv(&me, CMD_SQUIT, 0, "%s 0 :Server %s...",
+ cli_name(&me), what);
+ }
+ }
+
+ /* now let's perform the restart or exit */
flush_connections(0);
- close_connections(1);
- running = 0;
-
+
#if defined(DDB)
ddb_end();
#endif
+
+ log_close();
+ close_connections(!pe->restart ||
+ !(thisServer.bootopt & (BOOT_TTY | BOOT_DEBUG | BOOT_CHKCONF)));
+
+ if (!pe->restart) { /* just set running = 0 */
+ running = 0;
+ return;
+ }
+
+ /* OK, so we're restarting... */
+ reap_children();
+
+ execv(SPATH, thisServer.argv); /* restart the server */
+
+ /* something failed; reopen the logs so we can complain */
+ log_reopen();
+
+ log_write(LS_SYSTEM, L_CRIT, 0, "execv(%s,%s) failed: %m", SPATH,
+ *thisServer.argv);
+
+ Debug((DEBUG_FATAL, "Couldn't restart server \"%s\": %s", SPATH,
+ (strerror(errno)) ? strerror(errno) : ""));
+ exit(8);
}
-/*----------------------------------------------------------------------------
- * API: server_panic
- *--------------------------------------------------------------------------*/
-/** Immediately terminate the server with a message.
- * @param[in] message Message to log, but not send to operators.
+/**
+ * Issue server notice warning about impending restart or die.
+ * @param[in] pe Pointer to structure describing pending exit.
+ * @param[in] until How long until the exit (approximately).
*/
-void server_panic(const char *message)
+static void countdown_notice(struct PendingExit *pe, time_t until)
{
- /* inhibit sending server notice--we may be panicking due to low memory */
- log_write(LS_SYSTEM, L_CRIT, LOG_NOSNOTICE, "Server panic: %s", message);
- flush_connections(0);
- log_close();
- close_connections(1);
- exit(1);
+ const char *what = pe->restart ? "restarting" : "terminating";
+ const char *units;
+
+ if (until >= 60) { /* measure in minutes */
+ until /= 60; /* so convert it to minutes */
+ units = (until == 1) ? "minute" : "minutes";
+ } else
+ units = (until == 1) ? "second" : "seconds";
+
+ /* send the message */
+ if (pe->message)
+ sendto_lusers("Server %s in %d %s: %s", what, until, units, pe->message);
+ else
+ sendto_lusers("Server %s in %d %s...", what, until, units);
+}
+
+static void exit_countdown(struct Event *ev);
+
+/**
+ * Performs a delayed pending exit, issuing server notices as appropriate.
+ * Reschedules exit_countdown() as needed.
+ * @param[in] ev Timer event.
+ */
+static void _exit_countdown(struct PendingExit *pe, int do_notice)
+{
+ time_t total, next, approx;
+
+ if (CurrentTime >= pe->time) { /* time to do the exit */
+ pending_exit(pe);
+ return;
+ }
+
+ /* OK, we need to figure out how long to the next message and approximate
+ * how long until the actual exit.
+ */
+ total = pe->time - CurrentTime; /* how long until exit */
+
+#define t_adjust(interval, interval2) \
+ do { \
+ approx = next = total - (total % (interval)); \
+ if (next >= total - (interval2)) { \
+ next -= (interval); /* have to adjust next... */ \
+ if (next < (interval)) /* slipped into next interval */ \
+ next = (interval) - (interval2); \
+ } else /* have to adjust approx... */ \
+ approx += (interval); \
+ } while (0)
+
+ if (total > PEND_INT_LONG) /* in the long interval regime */
+ t_adjust(PEND_INT_LONG, PEND_INT_MEDIUM);
+ else if (total > PEND_INT_MEDIUM) /* in the medium interval regime */
+ t_adjust(PEND_INT_MEDIUM, PEND_INT_SHORT);
+ else if (total > PEND_INT_SHORT) /* in the short interval regime */
+ t_adjust(PEND_INT_SHORT, PEND_INT_END);
+ else if (total > PEND_INT_END) /* in the end interval regime */
+ t_adjust(PEND_INT_END, PEND_INT_LAST);
+ else if (total > PEND_INT_LAST) /* in the last message interval */
+ t_adjust(PEND_INT_LAST, PEND_INT_LAST);
+ else { /* next event is to actually exit */
+ next = 0;
+ approx = PEND_INT_LAST;
+ }
+
+ /* convert next to an absolute timestamp */
+ next = pe->time - next;
+ assert(next > CurrentTime);
+
+ /* issue the warning notices... */
+ if (do_notice)
+ countdown_notice(pe, approx);
+
+ /* reschedule the timer... */
+ timer_add(&countdown_timer, exit_countdown, pe, TT_ABSOLUTE, next);
}
-/*----------------------------------------------------------------------------
- * API: server_restart
- *--------------------------------------------------------------------------*/
-/** Restart the server with a message.
- * @param[in] message Message to log and send to operators.
+/**
+ * Timer callback for _exit_countdown().
+ * @param[in] ev Timer event.
*/
-void server_restart(const char *message)
+static void exit_countdown(struct Event *ev)
{
- static int restarting = 0;
+ if (ev_type(ev) == ET_DESTROY)
+ return; /* do nothing with destroy events */
+
+ assert(ET_EXPIRE == ev_type(ev));
+
+ /* perform the event we were called to do */
+ _exit_countdown(t_data(&countdown_timer), 1);
+}
- /* inhibit sending any server notices; we may be in a loop */
- log_write(LS_SYSTEM, L_WARNING, LOG_NOSNOTICE, "Restarting Server: %s",
- message);
- if (restarting++) /* increment restarting to prevent looping */
- return;
+/**
+ * Cancel a pending exit.
+ * @param[in] who Client cancelling the impending exit.
+ */
+void exit_cancel(struct Client *who)
+{
+ const char *what;
+ struct PendingExit *pe;
- sendto_opmask(0, SNO_OLDSNO, "Restarting server: %s", message);
- Debug((DEBUG_NOTICE, "Restarting server..."));
- flush_connections(0);
+ if (!t_onqueue(&countdown_timer))
+ return; /* it's not running... */
+
+ pe = t_data(&countdown_timer); /* get the pending exit data */
+ timer_del(&countdown_timer); /* delete the timer */
-#if defined(DDB)
- ddb_end();
-#endif
+ if (who) { /* explicitly issued cancellation */
+ /* issue a notice about the exit being canceled */
+ sendto_lusers("Server %s CANCELED",
+ what = (pe->restart ? "restart" : "termination"));
+
+ /* log the cancellation */
+ if (IsUser(who))
+ log_write(LS_SYSTEM, L_NOTICE, 0, "Server %s CANCELED by %s!%s@%s", what,
+ cli_name(who), cli_user(who)->username, cli_sockhost(who));
+ else
+ log_write(LS_SYSTEM, L_NOTICE, 0, "Server %s CANCELED by %s", what,
+ cli_name(who));
+ }
+
+ /* release the pending exit structure */
+ if (pe->who)
+ MyFree(pe->who);
+ if (pe->message)
+ MyFree(pe->message);
+ MyFree(pe);
- log_close();
+ /* Oh, and restore connections */
+ refuse = 0;
+}
- close_connections(!(thisServer.bootopt & (BOOT_TTY | BOOT_DEBUG | BOOT_CHKCONF)));
+/**
+ * Schedule a pending exit. Note that only real people issue delayed
+ * exits, so \a who should not be NULL if \a when is non-zero.
+ * @param[in] restart True if a restart is desired, false otherwise.
+ * @param[in] when Interval until the exit; 0 for immediate exit.
+ * @param[in] who Client issuing exit (or NULL).
+ * @param[in] message Message explaining exit.
+ */
+void exit_schedule(int restart, time_t when, struct Client *who,
+ const char *message)
+{
+ struct PendingExit *pe;
- reap_children();
+ /* first, let's cancel any pending exit */
+ exit_cancel(0);
+
+ /* now create a new pending exit */
+ pe = MyMalloc(sizeof(struct PendingExit));
+ pe->restart = restart;
+
+ pe->time = when + CurrentTime; /* make time absolute */
+ if (who) { /* save who issued it... */
+ if (IsUser(who)) {
+ char nuhbuf[NICKLEN + USERLEN + HOSTLEN + 3];
+ ircd_snprintf(0, nuhbuf, sizeof(nuhbuf), "%s!%s@%s", cli_name(who),
+ cli_user(who)->username, cli_sockhost(who));
+ DupString(pe->who, nuhbuf);
+ } else
+ DupString(pe->who, cli_name(who));
+ } else
+ pe->who = 0;
+ if (message) /* also save the message */
+ DupString(pe->message, message);
+ else
+ pe->message = 0;
- execv(SPATH, thisServer.argv);
+ /* let's refuse new connections... */
+ refuse = 1;
+
+ if (!when) { /* do it right now? */
+ pending_exit(pe);
+ return;
+ }
- /* Have to reopen since it has been closed above */
- log_reopen();
+ assert(who); /* only people issue delayed exits */
+
+ /* issue a countdown notice... */
+ countdown_notice(pe, when);
- log_write(LS_SYSTEM, L_CRIT, 0, "execv(%s,%s) failed: %m", SPATH,
- *thisServer.argv);
-
- Debug((DEBUG_FATAL, "Couldn't restart server \"%s\": %s",
- SPATH, (strerror(errno)) ? strerror(errno) : ""));
- exit(8);
+ /* log who issued the shutdown */
+ if (pe->message)
+ log_write(LS_SYSTEM, L_NOTICE, 0, "Delayed server %s issued by %s: %s",
+ restart ? "restart" : "termination", pe->who, pe->message);
+ else
+ log_write(LS_SYSTEM, L_NOTICE, 0, "Delayed server %s issued by %s...",
+ restart ? "restart" : "termination", pe->who);
+ /* and schedule the timer */
+ _exit_countdown(pe, 0);
}
+
+/*----------------------------------------------------------------------------
+ * API: server_panic
+ *--------------------------------------------------------------------------*/
+/** Immediately terminate the server with a message.
+ * @param[in] message Message to log, but not send to operators.
+ */
+void server_panic(const char *message)
+{
+ /* inhibit sending server notice--we may be panicking due to low memory */
+ log_write(LS_SYSTEM, L_CRIT, LOG_NOSNOTICE, "Server panic: %s", message);
+ flush_connections(0);
+ log_close();
+ close_connections(1);
+ exit(1);
+}
/*----------------------------------------------------------------------------
@@ -214,7 +423,7 @@
/** Handle out-of-memory condition. */
static void outofmemory(void) {
Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
- server_restart("Out of Memory");
+ exit_schedule(1, 0, 0, "Out of Memory");
}
@@ -767,6 +976,7 @@
timer_add(timer_init(&connect_timer), try_connections, 0, TT_RELATIVE, 1);
timer_add(timer_init(&ping_timer), check_pings, 0, TT_RELATIVE, 1);
timer_add(timer_init(&destruct_event_timer), exec_expired_destruct_events, 0, TT_PERIODIC, 60);
+ timer_init(&countdown_timer);
CurrentTime = time(NULL);
Modified: ircd/trunk/ircd/ircd_signal.c
===================================================================
--- ircd/trunk/ircd/ircd_signal.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/ircd_signal.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -89,7 +89,7 @@
assert(SIGTERM == sig_signal(ev_signal(ev)));
assert(SIGTERM == ev_data(ev));
- server_die("received signal SIGTERM");
+ exit_schedule(0, 0, 0, "Received signal SIGTERM");
}
/** Signal callback for SIGHUP.
@@ -116,7 +116,7 @@
assert(SIGINT == sig_signal(ev_signal(ev)));
assert(SIGINT == ev_data(ev));
- server_restart("caught signal: SIGINT");
+ exit_schedule(1, 0, 0, "Received signal SIGINT");
}
/** Allocate a child callback record.
Modified: ircd/trunk/ircd/m_die.c
===================================================================
--- ircd/trunk/ircd/m_die.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/m_die.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -68,7 +68,7 @@
sendcmdto_one(&me, CMD_ERROR, acptr, ":Terminated by %s",
get_client_name(sptr, HIDE_IP));
}
- server_die("received DIE");
+ exit_schedule(0, 0, 0, "Received DIE");
return 0;
}
Modified: ircd/trunk/ircd/m_restart.c
===================================================================
--- ircd/trunk/ircd/m_restart.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/m_restart.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -52,7 +52,7 @@
return send_reply(sptr, ERR_NOPRIVILEGES);
log_write(LS_SYSTEM, L_NOTICE, 0, "Server RESTART by %#C", sptr);
- server_restart("received RESTART");
+ exit_schedule(1, 0, 0, "Received RESTART");
return 0;
}
Modified: ircd/trunk/ircd/send.c
===================================================================
--- ircd/trunk/ircd/send.c 2008-08-15 18:11:20 UTC (rev 197)
+++ ircd/trunk/ircd/send.c 2008-08-15 18:54:05 UTC (rev 198)
@@ -895,3 +895,32 @@
msgq_clean(mb);
}
+
+/** Send a server notice to all local users on this server.
+ * @param[in] pattern Format string for server notice.
+ */
+void sendto_lusers(const char *pattern, ...)
+{
+ struct VarData vd;
+ struct Client *cptr;
+ struct MsgBuf *mb;
+ int i;
+
+ /* Build the message we're going to send... */
+ vd.vd_format = pattern;
+ va_start(vd.vd_args, pattern);
+ mb = msgq_make(0, ":%s " MSG_NOTICE " * :*** Notice -- %v", cli_name(&me),
+ &vd);
+ va_end(vd.vd_args);
+
+ /* send it along */
+ for (i = 0; i <= HighestFd; i++) {
+ if (!(cptr = LocalClientArray[i]) || !IsUser(cptr))
+ continue; /* skip empty slots... */
+
+ send_buffer(cptr, mb, 1); /* send with high priority */
+ }
+
+ msgq_clean(mb); /* clean up after ourselves */
+}
+
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|