static int tolua_faction_addnotice(lua_State * L) { faction *self = (faction *)tolua_tousertype(L, 1, 0); const char *str = tolua_tostring(L, 2, 0); addmessage(NULL, self, str, MSG_MESSAGE, ML_IMPORTANT); return 0; }
static int unitmessage_handle(trigger * t, void *data) { /* call an event handler on unitmessage. * data.v -> ( variant event, int timer ) */ unitmessage_data *td = (unitmessage_data *) t->data.v; if (td->target && td->target->no) { struct faction *f = td->target->faction; const char * str = LOC(f->locale, td->string); /* bug found in turn 733: sometimes, alps have f*cked up messages */ if (td->string && td->string[0]) { addmessage(td->target->region, f, str, td->type, td->level); } } unused_arg(data); return 0; }
int main(int argc, char *argv[]) { int daemonize = 0; char *pidfile = NULL; char *envarea = NULL; int cnid = -1; pcre *msgfilter = NULL; pcre *stdfilter = NULL; int argi; struct sigaction sa; RbtIterator handle; /* Dont save the error buffer */ save_errbuf = 0; /* Create the peer container */ peers = rbtNew(name_compare); for (argi=1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--debug")) { debug = 1; } else if (argnmatch(argv[argi], "--channel=")) { char *cn = strchr(argv[argi], '=') + 1; for (cnid = C_STATUS; (channelnames[cnid] && strcmp(channelnames[cnid], cn)); cnid++) ; if (channelnames[cnid] == NULL) cnid = -1; } else if (argnmatch(argv[argi], "--daemon")) { daemonize = 1; } else if (argnmatch(argv[argi], "--no-daemon")) { daemonize = 0; } else if (argnmatch(argv[argi], "--pidfile=")) { char *p = strchr(argv[argi], '='); pidfile = strdup(p+1); } else if (argnmatch(argv[argi], "--log=")) { char *p = strchr(argv[argi], '='); logfn = strdup(p+1); } else if (argnmatch(argv[argi], "--env=")) { char *p = strchr(argv[argi], '='); loadenv(p+1, envarea); } else if (argnmatch(argv[argi], "--area=")) { char *p = strchr(argv[argi], '='); envarea = strdup(p+1); } else if (argnmatch(argv[argi], "--locator=")) { char *p = strchr(argv[argi], '='); locator_init(p+1); locatorbased = 1; } else if (argnmatch(argv[argi], "--service=")) { char *p = strchr(argv[argi], '='); locatorservice = get_servicetype(p+1); } else if (argnmatch(argv[argi], "--filter=")) { char *p = strchr(argv[argi], '='); msgfilter = compileregex(p+1); if (!msgfilter) { errprintf("Invalid filter (bad expression): %s\n", p+1); } else { stdfilter = compileregex("^@@(logrotate|shutdown|drophost|droptest|renamehost|renametest)"); } } else { char *childcmd; char **childargs; int i = 0; childcmd = argv[argi]; childargs = (char **) calloc((1 + argc - argi), sizeof(char *)); while (argi < argc) { childargs[i++] = argv[argi++]; } addlocalpeer(childcmd, childargs); } } /* Sanity checks */ if (cnid == -1) { errprintf("No channel/unknown channel specified\n"); return 1; } if (locatorbased && (locatorservice == ST_MAX)) { errprintf("Must specify --service when using locator\n"); return 1; } if (!locatorbased && (rbtBegin(peers) == rbtEnd(peers))) { errprintf("Must specify command for local worker\n"); return 1; } /* Do cache responses to avoid doing too many lookups */ if (locatorbased) locator_prepcache(locatorservice, 0); /* Go daemon */ if (daemonize) { /* Become a daemon */ pid_t daemonpid = fork(); if (daemonpid < 0) { /* Fork failed */ errprintf("Could not fork child\n"); exit(1); } else if (daemonpid > 0) { /* Parent creates PID file and exits */ FILE *fd = NULL; if (pidfile) fd = fopen(pidfile, "w"); if (fd) { fprintf(fd, "%d\n", (int)daemonpid); fclose(fd); } exit(0); } /* Child (daemon) continues here */ setsid(); } /* Catch signals */ setup_signalhandler("xymond_channel"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sig_handler; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGCHLD, &sa, NULL); signal(SIGALRM, SIG_IGN); /* Switch stdout/stderr to the logfile, if one was specified */ freopen("/dev/null", "r", stdin); /* xymond_channel's stdin is not used */ if (logfn) { freopen(logfn, "a", stdout); freopen(logfn, "a", stderr); } /* Attach to the channel */ channel = setup_channel(cnid, CHAN_CLIENT); if (channel == NULL) { errprintf("Channel not available\n"); running = 0; } while (running) { /* * Wait for GOCLIENT to go up. * * Note that we use IPC_NOWAIT if there are messages in the * queue, because then we just want to pick up a message if * there is one, and if not we want to continue pushing the * queued data to the worker. */ struct sembuf s; int n; s.sem_num = GOCLIENT; s.sem_op = -1; s.sem_flg = ((pendingcount > 0) ? IPC_NOWAIT : 0); n = semop(channel->semid, &s, 1); if (n == 0) { /* * GOCLIENT went high, and so we got alerted about a new * message arriving. Copy the message to our own buffer queue. */ char *inbuf = NULL; if (!msgfilter || matchregex(channel->channelbuf, msgfilter) || matchregex(channel->channelbuf, stdfilter)) { inbuf = strdup(channel->channelbuf); } /* * Now we have safely stored the new message in our buffer. * Wait until any other clients on the same channel have picked up * this message (GOCLIENT reaches 0). * * We wrap this into an alarm handler, because it can occasionally * fail, causing the whole system to lock up. We dont want that.... * We'll set the alarm to trigger after 1 second. Experience shows * that we'll either succeed in a few milliseconds, or fail completely * and wait the full alarm-timer duration. */ gotalarm = 0; signal(SIGALRM, sig_handler); alarm(2); do { s.sem_num = GOCLIENT; s.sem_op = 0; s.sem_flg = 0; n = semop(channel->semid, &s, 1); } while ((n == -1) && (errno == EAGAIN) && running && (!gotalarm)); signal(SIGALRM, SIG_IGN); if (gotalarm) { errprintf("Gave up waiting for GOCLIENT to go low.\n"); } /* * Let master know we got it by downing BOARDBUSY. * This should not block, since BOARDBUSY is upped * by the master just before he ups GOCLIENT. */ do { s.sem_num = BOARDBUSY; s.sem_op = -1; s.sem_flg = IPC_NOWAIT; n = semop(channel->semid, &s, 1); } while ((n == -1) && (errno == EINTR)); if (n == -1) { errprintf("Tried to down BOARDBUSY: %s\n", strerror(errno)); } if (inbuf) { /* * See if they want us to rotate logs. We pass this on to * the worker module as well, but must handle our own logfile. */ if (strncmp(inbuf, "@@logrotate", 11) == 0) { freopen(logfn, "a", stdout); freopen(logfn, "a", stderr); } /* * Put the new message on our outbound queue. */ if (addmessage(inbuf) != 0) { /* Failed to queue message, free the buffer */ xfree(inbuf); } } } else { if (errno != EAGAIN) { dbgprintf("Semaphore wait aborted: %s\n", strerror(errno)); continue; } } /* * We've picked up messages from the master. Now we * must push them to the worker process. Since there * is no way to hang off both a semaphore and select(), * we'll just push as much data as possible into the * pipe. If we get to a point where we would block, * then wait a teeny bit of time and restart the * whole loop with checking for new messages from the * master etc. * * In theory, this could become an almost busy-wait loop. * In practice, however, the queue will be empty most * of the time because we'll just shove the data to the * worker child. */ for (handle = rbtBegin(peers); (handle != rbtEnd(peers)); handle = rbtNext(peers, handle)) { int canwrite = 1, hasfailed = 0; xymon_peer_t *pwalk; time_t msgtimeout = gettimer() - MSGTIMEOUT; int flushcount = 0; pwalk = (xymon_peer_t *) gettreeitem(peers, handle); if (pwalk->msghead == NULL) continue; /* Ignore peers with nothing queued */ switch (pwalk->peerstatus) { case P_UP: canwrite = 1; break; case P_DOWN: openconnection(pwalk); canwrite = (pwalk->peerstatus == P_UP); break; case P_FAILED: canwrite = 0; break; } /* See if we have stale messages queued */ while (pwalk->msghead && (pwalk->msghead->tstamp < msgtimeout)) { flushmessage(pwalk); flushcount++; } if (flushcount) { errprintf("Flushed %d stale messages for %s:%d\n", flushcount, inet_ntoa(pwalk->peeraddr.sin_addr), ntohs(pwalk->peeraddr.sin_port)); } while (pwalk->msghead && canwrite) { fd_set fdwrite; struct timeval tmo; /* Check that this peer is ready for writing. */ FD_ZERO(&fdwrite); FD_SET(pwalk->peersocket, &fdwrite); tmo.tv_sec = 0; tmo.tv_usec = 2000; n = select(pwalk->peersocket+1, NULL, &fdwrite, NULL, &tmo); if (n == -1) { errprintf("select() failed: %s\n", strerror(errno)); canwrite = 0; hasfailed = 1; continue; } else if ((n == 0) || (!FD_ISSET(pwalk->peersocket, &fdwrite))) { canwrite = 0; continue; } n = write(pwalk->peersocket, pwalk->msghead->bufp, pwalk->msghead->buflen); if (n >= 0) { pwalk->msghead->bufp += n; pwalk->msghead->buflen -= n; if (pwalk->msghead->buflen == 0) flushmessage(pwalk); } else if (errno == EAGAIN) { /* * Write would block ... stop for now. */ canwrite = 0; } else { hasfailed = 1; } if (hasfailed) { /* Write failed, or message grew stale */ errprintf("Peer at %s:%d failed: %s\n", inet_ntoa(pwalk->peeraddr.sin_addr), ntohs(pwalk->peeraddr.sin_port), strerror(errno)); canwrite = 0; shutdownconnection(pwalk); if (pwalk->peertype == P_NET) locator_serverdown(pwalk->peername, locatorservice); pwalk->peerstatus = P_FAILED; } } } } /* Detach from channels */ close_channel(channel, CHAN_CLIENT); /* Close peer connections */ for (handle = rbtBegin(peers); (handle != rbtEnd(peers)); handle = rbtNext(peers, handle)) { xymon_peer_t *pwalk = (xymon_peer_t *) gettreeitem(peers, handle); shutdownconnection(pwalk); } /* Remove the PID file */ if (pidfile) unlink(pidfile); return 0; }