static gboolean tcl_file_callback(GIOChannel *source, GIOCondition condition, gpointer data) { struct tcl_file_handler *tfh = data; struct tcl_file_event *fev; int mask = 0; if (condition & G_IO_IN) mask |= TCL_READABLE; if (condition & G_IO_OUT) mask |= TCL_WRITABLE; if (condition & (G_IO_ERR|G_IO_HUP|G_IO_NVAL)) mask |= TCL_EXCEPTION; if (!(tfh->mask & (mask & ~tfh->pending))) return TRUE; tfh->pending |= mask; fev = (struct tcl_file_event *)ckalloc(sizeof(struct tcl_file_event)); memset(fev, 0, sizeof(struct tcl_file_event)); fev->header.proc = tcl_file_event_callback; fev->fd = tfh->fd; Tcl_QueueEvent((Tcl_Event *)fev, TCL_QUEUE_TAIL); Tcl_ServiceAll(); return TRUE; }
static void tcl_create_file_handler(int fd, int mask, Tcl_FileProc *proc, ClientData data) { struct tcl_file_handler *tfh = g_new0(struct tcl_file_handler, 1); GIOChannel *channel; GIOCondition cond = 0; if (g_hash_table_lookup(tcl_file_handlers, GINT_TO_POINTER(fd))) tcl_delete_file_handler(fd); if (mask & TCL_READABLE) cond |= G_IO_IN; if (mask & TCL_WRITABLE) cond |= G_IO_OUT; if (mask & TCL_EXCEPTION) cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL; tfh->fd = fd; tfh->mask = mask; tfh->proc = proc; tfh->data = data; channel = g_io_channel_unix_new(fd); tfh->source = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, tcl_file_callback, tfh, g_free); g_io_channel_unref(channel); g_hash_table_insert(tcl_file_handlers, GINT_TO_POINTER(fd), tfh); Tcl_ServiceAll(); }
static gboolean tcl_kick(gpointer data) { tcl_timer_pending = FALSE; Tcl_ServiceAll(); return FALSE; }
static void TimerProc( ClientData clientData, /* Not used. */ XtIntervalId *id) { if (*id != notifier.currentTimeout) { return; } notifier.currentTimeout = 0; Tcl_ServiceAll(); }
static void tcl_delete_file_handler(int fd) { struct tcl_file_handler *tfh = g_hash_table_lookup(tcl_file_handlers, GINT_TO_POINTER(fd)); if (tfh == NULL) return; g_source_remove(tfh->source); g_hash_table_remove(tcl_file_handlers, GINT_TO_POINTER(fd)); Tcl_ServiceAll(); }
static void FileProc( ClientData clientData, int *fd, XtInputId *id) { FileHandler *filePtr = (FileHandler *)clientData; FileHandlerEvent *fileEvPtr; int mask = 0; /* * Determine which event happened. */ if (*id == filePtr->read) { mask = TCL_READABLE; } else if (*id == filePtr->write) { mask = TCL_WRITABLE; } else if (*id == filePtr->except) { mask = TCL_EXCEPTION; } /* * Ignore unwanted or duplicate events. */ if (!(filePtr->mask & mask) || (filePtr->readyMask & mask)) { return; } /* * This is an interesting event, so put it onto the event queue. */ filePtr->readyMask |= mask; fileEvPtr = ckalloc(sizeof(FileHandlerEvent)); fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); /* * Process events on the Tcl event queue before returning to Xt. */ Tcl_ServiceAll(); }
int mainloop(int toplevel) { static int socket_cleanup = 0; int xx, i, eggbusy = 1, tclbusy = 0; char buf[520]; /* Lets move some of this here, reducing the numer of actual * calls to periodic_timers */ now = time(NULL); /* * FIXME: Get rid of this, it's ugly and wastes lots of cpu. * * pre-1.3.0 Eggdrop had random() in the once a second block below. * * This attempts to keep random() more random by constantly * calling random() and updating the state information. */ random(); /* Woop, lets really jumble things */ /* If we want to restart, we have to unwind to the toplevel. * Tcl will Panic if we kill the interp with Tcl_Eval in progress. * This is done by returning -1 in tickle_WaitForEvent. */ if (do_restart && do_restart != -2 && !toplevel) return -1; /* Once a second */ if (now != then) { call_hook(HOOK_SECONDLY); then = now; } /* Only do this every so often. */ if (!socket_cleanup) { socket_cleanup = 5; /* Remove dead dcc entries. */ dcc_remove_lost(); /* Check for server or dcc activity. */ dequeue_sockets(); } else socket_cleanup--; /* Free unused structures. */ garbage_collect(); xx = sockgets(buf, &i); if (xx >= 0) { /* Non-error */ int idx; for (idx = 0; idx < dcc_total; idx++) if (dcc[idx].sock == xx) { if (dcc[idx].type && dcc[idx].type->activity) { /* Traffic stats */ if (dcc[idx].type->name) { if (!strncmp(dcc[idx].type->name, "BOT", 3)) itraffic_bn_today += strlen(buf) + 1; else if (!strcmp(dcc[idx].type->name, "SERVER")) itraffic_irc_today += strlen(buf) + 1; else if (!strncmp(dcc[idx].type->name, "CHAT", 4)) itraffic_dcc_today += strlen(buf) + 1; else if (!strncmp(dcc[idx].type->name, "FILES", 5)) itraffic_dcc_today += strlen(buf) + 1; else if (!strcmp(dcc[idx].type->name, "SEND")) itraffic_trans_today += strlen(buf) + 1; else if (!strncmp(dcc[idx].type->name, "GET", 3)) itraffic_trans_today += strlen(buf) + 1; else itraffic_unknown_today += strlen(buf) + 1; } dcc[idx].type->activity(idx, buf, i); } else putlog(LOG_MISC, "*", "!!! untrapped dcc activity: type %s, sock %d", dcc[idx].type->name, dcc[idx].sock); break; } } else if (xx == -1) { /* EOF from someone */ int idx; if (i == STDOUT && !backgrd) fatal("END OF FILE ON TERMINAL", 0); for (idx = 0; idx < dcc_total; idx++) if (dcc[idx].sock == i) { if (dcc[idx].type && dcc[idx].type->eof) dcc[idx].type->eof(idx); else { putlog(LOG_MISC, "*", "*** ATTENTION: DEAD SOCKET (%d) OF TYPE %s UNTRAPPED", i, dcc[idx].type ? dcc[idx].type->name : "*UNKNOWN*"); killsock(i); lostdcc(idx); } idx = dcc_total + 1; } if (idx == dcc_total) { putlog(LOG_MISC, "*", "(@) EOF socket %d, not a dcc socket, not anything.", i); close(i); killsock(i); } } else if (xx == -2 && errno != EINTR) { /* select() error */ putlog(LOG_MISC, "*", "* Socket error #%d; recovering.", errno); for (i = 0; i < dcc_total; i++) { if ((fcntl(dcc[i].sock, F_GETFD, 0) == -1) && (errno == EBADF)) { putlog(LOG_MISC, "*", "DCC socket %d (type %d, name '%s') expired -- pfft", dcc[i].sock, dcc[i].type, dcc[i].nick); killsock(dcc[i].sock); lostdcc(i); i--; } } } else if (xx == -3) { call_hook(HOOK_IDLE); socket_cleanup = 0; /* If we've been idle, cleanup & flush */ eggbusy = 0; } else if (xx == -5) { eggbusy = 0; tclbusy = 1; } if (do_restart) { if (do_restart == -2) rehash(); else if (!toplevel) return -1; /* Unwind to toplevel before restarting */ else { /* Unload as many modules as possible */ int f = 1; module_entry *p; Function startfunc; char name[256]; /* oops, I guess we should call this event before tcl is restarted */ check_tcl_event("prerestart"); while (f) { f = 0; for (p = module_list; p != NULL; p = p->next) { dependancy *d = dependancy_list; int ok = 1; while (ok && d) { if (d->needed == p) ok = 0; d = d->next; } if (ok) { strcpy(name, p->name); if (module_unload(name, botnetnick) == NULL) { f = 1; break; } } } } /* Make sure we don't have any modules left hanging around other than * "eggdrop" and the two that are supposed to be. */ for (f = 0, p = module_list; p; p = p->next) { if (strcmp(p->name, "eggdrop") && strcmp(p->name, "encryption") && strcmp(p->name, "uptime")) { f++; } } if (f != 0) { putlog(LOG_MISC, "*", MOD_STAGNANT); } flushlogs(); kill_tcl(); init_tcl(argc, argv); init_language(0); /* this resets our modules which we didn't unload (encryption and uptime) */ for (p = module_list; p; p = p->next) { if (p->funcs) { startfunc = p->funcs[MODCALL_START]; startfunc(NULL); } } rehash(); #ifdef TLS ssl_cleanup(); ssl_init(); #endif restart_chons(); call_hook(HOOK_LOADED); } eggbusy = 1; do_restart = 0; } #ifdef USE_TCL_EVENTS if (!eggbusy) { /* Process all pending tcl events */ # ifdef REPLACE_NOTIFIER if (Tcl_ServiceAll()) tclbusy = 1; # else while (Tcl_DoOneEvent(TCL_DONT_WAIT | TCL_ALL_EVENTS)) tclbusy = 1; # endif /* REPLACE_NOTIFIER */ #endif /* USE_TCL_EVENTS */ } return (eggbusy || tclbusy); }
/* We don't need a re-entrancy guard on Windows as Tcl_ServiceAll has one -- it uses serviceMode, setting it to TCL_SERVICE_NONE whilst it is running. Unlike TclDoOneEvent, it checks on entry. */ static void TclSpinLoop(void *data) { Tcl_ServiceAll(); }