Example #1
0
File: mic.c Project: naeems/bkvoice
void * network_recv_thread(void *p)
{
    struct sockaddr_in remote_addr;
    int result;
    int socklen;
#if RECORD_RECV_PCM 
    FILE * fp = fopen("recv.pcm", "wb");
    if(!fp)
    {
        perror("open file");
    }
#endif
    
    printf("数据接收开始\n");
    socklen = sizeof(struct sockaddr);
    while(flag_network_recv)
    {
        printf("recv\n");
        {      
            result = recvfrom(fdsocket, pWriteHeader->buffer_capture, sizeof(pWriteHeader->buffer_capture)+sizeof(int)+sizeof(int), 
                0, (struct sockaddr*)&remote_addr, &socklen);

            if(result == -1)
            {
                    perror("data recv");
                    return;
            }
            else
            {
#if RECORD_RECV_PCM 
                fwrite(pWriteHeader->buffer, SAMPLERATE/1000*READMSFORONCE*sizeof(short), 1, fp);
#endif
                traceprintf("收到数据 %d byte\n", result);
            }
        }
    }
#if RECORD_RECV_PCM 
    fclose(fp);
#endif    
    printf("数据接收线程已经关闭 data recv thread is closed\n");
    close(fdsocket);    
}
Example #2
0
int main(int argc, char *argv[])
{
	char *msg;
	int seq;
	int argi;
	int alertcolors, alertinterval;
	char *configfn = NULL;
	char *checkfn = NULL;
	int checkpointinterval = 900;
	char acklogfn[PATH_MAX];
	FILE *acklogfd = NULL;
	char notiflogfn[PATH_MAX];
	FILE *notiflogfd = NULL;
	char *tracefn = NULL;
	struct sigaction sa;
	int configchanged;
	time_t lastxmit = 0;

	MEMDEFINE(acklogfn);
	MEMDEFINE(notiflogfn);

	libxymon_init(argv[0]);

	/* Dont save the error buffer */
	save_errbuf = 0;

	/* Load alert config */
	alertcolors = colorset(xgetenv("ALERTCOLORS"), ((1 << COL_GREEN) | (1 << COL_BLUE)));
	alertinterval = 60*atoi(xgetenv("ALERTREPEAT"));

	/* Create our loookup-trees */
	hostnames = xtreeNew(strcasecmp);
	testnames = xtreeNew(strcasecmp);
	locations = xtreeNew(strcasecmp);

	for (argi=1; (argi < argc); argi++) {
		if (argnmatch(argv[argi], "--config=")) {
			configfn = strdup(strchr(argv[argi], '=')+1);
		}
		else if (argnmatch(argv[argi], "--checkpoint-file=")) {
			checkfn = strdup(strchr(argv[argi], '=')+1);
		}
		else if (argnmatch(argv[argi], "--checkpoint-interval=")) {
			char *p = strchr(argv[argi], '=') + 1;
			checkpointinterval = atoi(p);
		}
		else if (argnmatch(argv[argi], "--dump-config")) {
			load_alertconfig(configfn, alertcolors, alertinterval);
			dump_alertconfig(1);
			return 0;
		}
		else if (argnmatch(argv[argi], "--cfid")) {
			include_configid = 1;
		}
		else if (argnmatch(argv[argi], "--test")) {
			char *testhost = NULL, *testservice = NULL, *testpage = NULL, 
			     *testcolor = "red", *testgroups = NULL;
			void *hinfo;
			int testdur = 0;
			FILE *logfd = NULL;
			activealerts_t *awalk = NULL;
			int paramno = 0;

			argi++; if (argi < argc) testhost = argv[argi];
			argi++; if (argi < argc) testservice = argv[argi];
			argi++; 
			while (argi < argc) {
				if (strncasecmp(argv[argi], "--duration=", 11) == 0) {
					testdur = durationvalue(strchr(argv[argi], '=')+1);
				}
				else if (strncasecmp(argv[argi], "--color=", 8) == 0) {
					testcolor = strchr(argv[argi], '=')+1;
				}
				else if (strncasecmp(argv[argi], "--group=", 8) == 0) {
					testgroups = strchr(argv[argi], '=')+1;
				}
				else if (strncasecmp(argv[argi], "--time=", 7) == 0) {
					fakestarttime = (time_t)atoi(strchr(argv[argi], '=')+1);
				}
				else {
					paramno++;
					if (paramno == 1) testdur = atoi(argv[argi]);
					else if (paramno == 2) testcolor = argv[argi];
					else if (paramno == 3) fakestarttime = (time_t) atoi(argv[argi]);
				}

				argi++;
			}

			if ((testhost == NULL) || (testservice == NULL)) {
				printf("Usage: xymond_alert --test HOST SERVICE [options]\n");
				printf("Possible options:\n\t[--duration=MINUTES]\n\t[--color=COLOR]\n\t[--group=GROUPNAME]\n\t[--time=TIMESPEC]\n");

				return 1;
			}

			load_hostnames(xgetenv("HOSTSCFG"), NULL, get_fqdn());
			hinfo = hostinfo(testhost);
			if (hinfo) {
				testpage = strdup(xmh_item(hinfo, XMH_ALLPAGEPATHS));
			}
			else {
				errprintf("Host not found in hosts.cfg - assuming it is on the top page\n");
				testpage = "";
			}

			awalk = (activealerts_t *)calloc(1, sizeof(activealerts_t));
			awalk->hostname = find_name(hostnames, testhost);
			awalk->testname = find_name(testnames, testservice);
			awalk->location = find_name(locations, testpage);
			awalk->ip = strdup("127.0.0.1");
			awalk->color = awalk->maxcolor = parse_color(testcolor);
			awalk->pagemessage = "Test of the alert configuration";
			awalk->eventstart = getcurrenttime(NULL) - testdur*60;
			awalk->groups = (testgroups ? strdup(testgroups) : NULL);
			awalk->state = A_PAGING;
			awalk->cookie = 12345;
			awalk->next = NULL;

			logfd = fopen("/dev/null", "w");
			starttrace(NULL);
			testonly = 1;

			load_alertconfig(configfn, alertcolors, alertinterval);
			load_holidays(0);
			send_alert(awalk, logfd);
			return 0;
		}
		else if (argnmatch(argv[argi], "--trace=")) {
			tracefn = strdup(strchr(argv[argi], '=')+1);
			starttrace(tracefn);
		}
		else if (net_worker_option(argv[argi])) {
			/* Handled in the subroutine */
		}
		else if (standardoption(argv[argi])) {
			if (showhelp) return 0;
		}
		else {
			errprintf("Unknown option '%s'\n", argv[argi]);
		}
	}

	/* Do the network stuff if needed */
	net_worker_run(ST_ALERT, LOC_SINGLESERVER, NULL);

	if (checkfn) {
		load_checkpoint(checkfn);
		nextcheckpoint = gettimer() + checkpointinterval;
		dbgprintf("Next checkpoint at %d, interval %d\n", (int) nextcheckpoint, checkpointinterval);
	}

	setup_signalhandler("xymond_alert");
	/* Need to handle these ourselves, so we can shutdown and save state-info */
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = sig_handler;
	sigaction(SIGPIPE, &sa, NULL);
	sigaction(SIGTERM, &sa, NULL);
	sigaction(SIGINT,  &sa, NULL);
	sigaction(SIGCHLD, &sa, NULL);
	sigaction(SIGUSR1, &sa, NULL);
	sigaction(SIGHUP,  &sa, NULL);

	if (xgetenv("XYMONSERVERLOGS")) {
		sprintf(acklogfn, "%s/acknowledge.log", xgetenv("XYMONSERVERLOGS"));
		acklogfd = fopen(acklogfn, "a");
		sprintf(notiflogfn, "%s/notifications.log", xgetenv("XYMONSERVERLOGS"));
		notiflogfd = fopen(notiflogfn, "a");
	}

	/*
	 * The general idea here is that this loop handles receiving of alert-
	 * and ack-messages from the master daemon, and maintains a list of 
	 * host+test combinations that may have alerts going out.
	 *
	 * This module does not deal with any specific alert-configuration, 
	 * it just picks up the alert messages, maintains the list of 
	 * known tests that are in some sort of critical condition, and
	 * periodically pushes alerts to the do_alert.c module for handling.
	 *
	 * The only modification of alerts that happen here is the handling
	 * of when the next alert is due. It calls into the next_alert() 
	 * routine to learn when an alert should be repeated, and also 
	 * deals with Acknowledgments that stop alerts from going out for
	 * a period of time.
	 */
	while (running) {
		char *eoln, *restofmsg;
		char *metadata[20];
		char *p;
		int metacount;
		char *hostname = NULL, *testname = NULL;
		struct timespec timeout;
		time_t now, nowtimer;
		int anytogo;
		activealerts_t *awalk;
		int childstat;

		nowtimer = gettimer();
		if (checkfn && (nowtimer > nextcheckpoint)) {
			dbgprintf("Saving checkpoint\n");
			nextcheckpoint = nowtimer + checkpointinterval;
			save_checkpoint(checkfn);

			if (acklogfd) acklogfd = freopen(acklogfn, "a", acklogfd);
			if (notiflogfd) notiflogfd = freopen(notiflogfn, "a", notiflogfd);
		}

		timeout.tv_sec = 60; timeout.tv_nsec = 0;
		msg = get_xymond_message(C_PAGE, "xymond_alert", &seq, &timeout);
		if (msg == NULL) {
			running = 0;
			continue;
		}

		/* See what time it is - must happen AFTER the timeout */
		now = getcurrenttime(NULL);

		/* Split the message in the first line (with meta-data), and the rest */
 		eoln = strchr(msg, '\n');
		if (eoln) {
			*eoln = '\0';
			restofmsg = eoln+1;
		}
		else {
			restofmsg = "";
		}

		/* 
		 * Now parse the meta-data into elements.
		 * We use our own "gettok()" routine which works
		 * like strtok(), but can handle empty elements.
		 */
		metacount = 0; 
		memset(&metadata, 0, sizeof(metadata));
		p = gettok(msg, "|");
		while (p && (metacount < 19)) {
			metadata[metacount] = p;
			metacount++;
			p = gettok(NULL, "|");
		}
		metadata[metacount] = NULL;

		if (metacount > 3) hostname = metadata[3];
		if (metacount > 4) testname = metadata[4];

		if ((metacount > 10) && (strncmp(metadata[0], "@@page", 6) == 0)) {
			/* @@page|timestamp|sender|hostname|testname|hostip|expiretime|color|prevcolor|changetime|location|cookie|osname|classname|grouplist|modifiers */

			int newcolor, newalertstatus, oldalertstatus;

			dbgprintf("Got page message from %s:%s\n", hostname, testname);
			traceprintf("@@page %s:%s:%s=%s\n", hostname, testname, metadata[10], metadata[7]);

			awalk = find_active(hostname, testname);
			if (awalk == NULL) {
				char *hwalk = find_name(hostnames, hostname);
				char *twalk = find_name(testnames, testname);
				char *pwalk = find_name(locations, metadata[10]);

				awalk = (activealerts_t *)calloc(1, sizeof(activealerts_t));
				awalk->hostname = hwalk;
				awalk->testname = twalk;
				awalk->location = pwalk;
				awalk->cookie = -1;
				awalk->state = A_DEAD;
				/*
				 * Use changetime here, if we restart the alert module then
				 * this gets the duration values more right than using "now".
				 * Also, define this only when a new alert arrives - we should
				 * NOT clear this when a status goes yellow->red, or if it
				 * flaps between yellow and red.
				 */
				awalk->eventstart = atoi(metadata[9]);
				add_active(awalk->hostname, awalk);
				traceprintf("New record\n");
			}

			newcolor = parse_color(metadata[7]);
			oldalertstatus = ((alertcolors & (1 << awalk->color)) != 0);
			newalertstatus = ((alertcolors & (1 << newcolor)) != 0);

			traceprintf("state %d->%d\n", oldalertstatus, newalertstatus);

			if (newalertstatus) {
				/* It's in an alert state. */
				awalk->color = newcolor;
				awalk->state = A_PAGING;

				if (newcolor > awalk->maxcolor) {
					if (awalk->maxcolor != 0) {
						/*
						 * Severity has increased (yellow -> red).
						 * Clear the repeat-interval, and set maxcolor to
						 * the new color. If it drops to yellow again,
						 * maxcolor stays at red, so a test that flaps
						 * between yellow and red will only alert on red
						 * the first time, and then follow the repeat
						 * interval.
						 */
						dbgprintf("Severity increased, cleared repeat interval: %s/%s %s->%s\n",
							awalk->hostname, awalk->testname,
							colorname(awalk->maxcolor), colorname(newcolor));
						clear_interval(awalk);
					}

					awalk->maxcolor = newcolor;
				}
			}
			else {
				/* 
				 * Send one "recovered" message out now, then go to A_DEAD.
				 * Dont update the color here - we want recoveries to go out 
				 * only if the alert color triggered an alert
				 */
				awalk->state = (newcolor == COL_BLUE) ? A_DISABLED : A_RECOVERED;
			}

			if (oldalertstatus != newalertstatus) {
				dbgprintf("Alert status changed from %d to %d\n", oldalertstatus, newalertstatus);
				clear_interval(awalk);
			}

			if (awalk->ip) xfree(awalk->ip);
			awalk->ip = strdup(metadata[5]);
			awalk->cookie = atoi(metadata[11]);
			if (awalk->osname) xfree(awalk->osname);
			awalk->osname    = (metadata[12] ? strdup(metadata[12]) : NULL);
			if (awalk->classname) xfree(awalk->classname);
			awalk->classname = (metadata[13] ? strdup(metadata[13]) : NULL);
			if (awalk->groups) xfree(awalk->groups);
			awalk->groups    = (metadata[14] ? strdup(metadata[14]) : NULL);
			if (awalk->pagemessage) xfree(awalk->pagemessage);
			if (metadata[15]) {
				/* Modifiers are more interesting than the message itself */
				awalk->pagemessage = (char *)malloc(strlen(awalk->hostname) + strlen(awalk->testname) + strlen(colorname(awalk->color)) + strlen(metadata[15]) + strlen(restofmsg) + 10);
				sprintf(awalk->pagemessage, "%s:%s %s\n%s\n%s",
					awalk->hostname, awalk->testname, colorname(awalk->color), metadata[15], restofmsg);
			}
			else {
				awalk->pagemessage = strdup(restofmsg);
			}
		}
		else if ((metacount > 5) && (strncmp(metadata[0], "@@ack", 5) == 0)) {
 			/* @@ack|timestamp|sender|hostname|testname|hostip|expiretime */

			/*
			 * An ack is handled simply by setting the next
			 * alert-time to when the ack expires.
			 */
			time_t nextalert = atoi(metadata[6]);

			dbgprintf("Got ack message from %s:%s\n", hostname, testname);
			traceprintf("@@ack: %s:%s now=%d, ackeduntil %d\n",
				     hostname, testname, (int)now, (int)nextalert);

			awalk = find_active(hostname, testname);

			if (acklogfd) {
				int cookie = (awalk ? awalk->cookie : -1);
				int color  = (awalk ? awalk->color : 0);

				fprintf(acklogfd, "%d\t%d\t%d\t%d\t%s\t%s.%s\t%s\t%s\n",
					(int)now, cookie, 
					(int)((nextalert - now) / 60), cookie,
					"np_filename_not_used", 
					hostname, testname, 
					colorname(color),
					nlencode(restofmsg));
				fflush(acklogfd);
			}

			if (awalk && (awalk->state == A_PAGING)) {
				traceprintf("Record updated\n");
				awalk->state = A_ACKED;
				awalk->nextalerttime = nextalert;
				if (awalk->ackmessage) xfree(awalk->ackmessage);
				awalk->ackmessage = strdup(restofmsg);
			}
			else {
				traceprintf("No record\n");
			}
		}
		else if ((metacount > 4) && (strncmp(metadata[0], "@@notify", 5) == 0)) {
			/* @@notify|timestamp|sender|hostname|testname|pagepath */

			char *hwalk = find_name(hostnames, hostname);
			char *twalk = find_name(testnames, testname);
			char *pwalk = find_name(locations, (metadata[5] ? metadata[5] : ""));

			awalk = (activealerts_t *)calloc(1, sizeof(activealerts_t));
			awalk->hostname = hwalk;
			awalk->testname = twalk;
			awalk->location = pwalk;
			awalk->cookie = -1;
			awalk->pagemessage = strdup(restofmsg);
			awalk->eventstart = getcurrenttime(NULL);
			awalk->state = A_NOTIFY;
			add_active(awalk->hostname, awalk);
		}
		else if ((metacount > 3) && 
			 ((strncmp(metadata[0], "@@drophost", 10) == 0) || (strncmp(metadata[0], "@@dropstate", 11) == 0))) {
			/* @@drophost|timestamp|sender|hostname */
			/* @@dropstate|timestamp|sender|hostname */
			xtreePos_t handle;

			handle = xtreeFind(hostnames, hostname);
			if (handle != xtreeEnd(hostnames)) {
				alertanchor_t *anchor = (alertanchor_t *)xtreeData(hostnames, handle);
				for (awalk = anchor->head; (awalk); awalk = awalk->next) awalk->state = A_DEAD;
			}
		}
		else if ((metacount > 4) && (strncmp(metadata[0], "@@droptest", 10) == 0)) {
			/* @@droptest|timestamp|sender|hostname|testname */

			awalk = find_active(hostname, testname);
			if (awalk) awalk->state = A_DEAD;
		}
		else if ((metacount > 4) && (strncmp(metadata[0], "@@renamehost", 12) == 0)) {
			/* @@renamehost|timestamp|sender|hostname|newhostname */

			/* 
			 * We handle rename's simply by dropping the alert. If there is still an
			 * active alert for the host, it will have to be dealt with when the next
			 * status update arrives.
			 */
			xtreePos_t handle;

			handle = xtreeFind(hostnames, hostname);
			if (handle != xtreeEnd(hostnames)) {
				alertanchor_t *anchor = (alertanchor_t *)xtreeData(hostnames, handle);
				for (awalk = anchor->head; (awalk); awalk = awalk->next) awalk->state = A_DEAD;
			}
		}
		else if ((metacount > 5) && (strncmp(metadata[0], "@@renametest", 12) == 0)) {
			/* @@renametest|timestamp|sender|hostname|oldtestname|newtestname */

			/* 
			 * We handle rename's simply by dropping the alert. If there is still an
			 * active alert for the host, it will have to be dealt with when the next
			 * status update arrives.
			 */
			awalk = find_active(hostname, testname);
			if (awalk) awalk->state = A_DEAD;
		}
		else if (strncmp(metadata[0], "@@shutdown", 10) == 0) {
			running = 0;
			errprintf("Got a shutdown message\n");
			continue;
		}
		else if (strncmp(metadata[0], "@@logrotate", 11) == 0) {
			char *fn = xgetenv("XYMONCHANNEL_LOGFILENAME");
			if (fn && strlen(fn)) {
				reopen_file(fn, "a", stdout);
				reopen_file(fn, "a", stderr);

				if (tracefn) {
					stoptrace();
					starttrace(tracefn);
				}
			}
			continue;
		}
		else if (strncmp(metadata[0], "@@reload", 8) == 0) {
			/* Nothing ... right now */
		}
		else if (strncmp(metadata[0], "@@idle", 6) == 0) {
			/* Timeout */
		}

		/*
		 * When a burst of alerts happen, we get lots of alert messages
		 * coming in quickly. So lets handle them in bunches and only 
		 * do the full alert handling once every 10 secs - that lets us
		 * combine a bunch of alerts into one transmission process.
		 */
		if (nowtimer < (lastxmit+10)) continue;
		lastxmit = nowtimer;

		/* 
		 * Loop through the activealerts list and see if anything is pending.
		 * This is an optimization, we could just as well just fork off the
		 * notification child and let it handle all of it. But there is no
		 * reason to fork a child process unless it is going to do something.
		 */
		configchanged = load_alertconfig(configfn, alertcolors, alertinterval);
		configchanged += load_holidays(0);
		anytogo = 0;
		for (awalk = alistBegin(); (awalk); awalk = alistNext()) {
			int anymatch = 0;

			switch (awalk->state) {
			  case A_NORECIP:
				if (!configchanged) break;

				/* The configuration has changed - switch NORECIP -> PAGING */
				awalk->state = A_PAGING;
				clear_interval(awalk);
				/* Fall through */

			  case A_PAGING:
				if (have_recipient(awalk, &anymatch)) {
					if (awalk->nextalerttime <= now) anytogo++;
				}
				else {
					if (!anymatch) {
						awalk->state = A_NORECIP;
						cleanup_alert(awalk);
					}
				}
				break;

			  case A_ACKED:
				if (awalk->nextalerttime <= now) {
					/* An ack has expired, so drop the ack message and switch to A_PAGING */
					anytogo++;
					if (awalk->ackmessage) xfree(awalk->ackmessage);
					awalk->state = A_PAGING;
				}
				break;

			  case A_RECOVERED:
			  case A_DISABLED:
			  case A_NOTIFY:
				anytogo++;
				break;

			  case A_DEAD:
				break;
			}
		}
		dbgprintf("%d alerts to go\n", anytogo);

		if (anytogo) {
			pid_t childpid;

			childpid = fork();
			if (childpid == 0) {
				/* The child */
				start_alerts();
				for (awalk = alistBegin(); (awalk); awalk = alistNext()) {
					switch (awalk->state) {
					  case A_PAGING:
						if (awalk->nextalerttime <= now) {
							send_alert(awalk, notiflogfd);
						}
						break;

					  case A_ACKED:
						/* Cannot be A_ACKED unless the ack is still valid, so no alert. */
						break;

					  case A_RECOVERED:
					  case A_DISABLED:
					  case A_NOTIFY:
						send_alert(awalk, notiflogfd);
						break;

					  case A_NORECIP:
					  case A_DEAD:
						break;
					}
				}
				finish_alerts();

				/* Child does not continue */
				exit(0);
			}
			else if (childpid < 0) {
				errprintf("Fork failed, cannot send alerts: %s\n", strerror(errno));
			}
		}

		/* Update the state flag and the next-alert timestamp */
		for (awalk = alistBegin(); (awalk); awalk = alistNext()) {
			switch (awalk->state) {
			  case A_PAGING:
				if (awalk->nextalerttime <= now) awalk->nextalerttime = next_alert(awalk);
				break;

			  case A_NORECIP:
				break;

			  case A_ACKED:
				/* Still cannot get here except if ack is still valid */
				break;

			  case A_RECOVERED:
			  case A_DISABLED:
			  case A_NOTIFY:
				awalk->state = A_DEAD;
				/* Fall through */

			  case A_DEAD:
				cleanup_alert(awalk); 
				break;
			}
		}

		clean_all_active();

		/* Pickup any finished child processes to avoid zombies */
		while (wait3(&childstat, WNOHANG, NULL) > 0) ;
	}

	if (checkfn) save_checkpoint(checkfn);
	if (acklogfd) fclose(acklogfd);
	if (notiflogfd) fclose(notiflogfd);
	stoptrace();

	MEMUNDEFINE(notiflogfn);
	MEMUNDEFINE(acklogfn);

	if (termsig >= 0) {
		errprintf("Terminated by signal %d\n", termsig);
	}

	return 0;
}
Example #3
0
File: mic.c Project: naeems/bkvoice
void * network_send_thread(void *p)
{
    int result;
#if SPEEX_AUDIO_CODEC
    char cbits[500];
    //int nbBytes;
    void *state;
    SpeexBits bits;
    int tmp;
    SpeexPreprocessState *st;
    float f;
#endif

#if SPEEX_AUDIO_CODEC

#if VAD_ENABLED
   st = speex_preprocess_state_init(SAMPLERATE/1000*READMSFORONCE, SAMPLERATE);
   tmp=1;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
    tmp=1;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_VAD, &tmp);

   tmp=1;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &tmp);
   tmp=8000;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &tmp);
   tmp=1;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
   f=.0;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
   f=.0;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
#endif



    /*Create a new encoder state in narrowband mode*/
    state = speex_encoder_init(&speex_uwb_mode);

    /*Set the quality to 8 (15 kbps)*/
    tmp=8;
    speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp);

    //复杂度
    tmp = 1;
    speex_encoder_ctl(state, SPEEX_SET_COMPLEXITY, &tmp); 

    tmp=1;
    speex_encoder_ctl(state, SPEEX_SET_VBR, &tmp); //使能VBR数据质量
    /*Initialization of the structure that holds the bits*/
   speex_bits_init(&bits);
#endif


#if RECORD_SEND_PCM
    FILE *fp = fopen("send.pcm", "wb");
#endif

#if RECORD_ENCODE_FILE
    FILE *fp_encode = fopen("send.bits", "wb");
#endif

    socklen_t socklen;
    printf("数据发送开始\n");
    socklen = sizeof(struct sockaddr);
    while(flag_network_send)
    {
        sem_wait(&sem_capture);//等待采集线程有数据
        if(n > 0)
        {      
                traceprintf("等待 sem_capture 信号量\n");

                if(!pReadHeader->Valid) 
                {
                    printf("忽略%d\n", pReadHeader->FrameNO);
                    continue;
                }


#if SPEEX_AUDIO_CODEC

            speex_bits_reset(&bits);

            /*Encode the frame*/
            speex_encode_int(state, pReadHeader->buffer_capture, &bits);

            /*Copy the bits to an array of char that can be written*/
            pReadHeader->count_encode = speex_bits_write(&bits, pReadHeader->buffer_encode, 200);
            //printf("压缩后大小 %d\n", pReadHeader->count_encode);
#if RECORD_ENCODE_FILE
            fwrite(&(pReadHeader->count_encode), sizeof(int), 1, fp_encode); 
            fwrite(pReadHeader->buffer_encode, pReadHeader->count_encode, 1, fp_encode);
#endif


#if VAD_ENABLED
            pReadHeader->vad = speex_preprocess_run(st, pReadHeader->buffer_capture);
#endif

#endif


#if TRAN_MODE==UDP_MODE
#if SILK_AUDIO_CODEC || SPEEX_AUDIO_CODEC
                //printf("发送%d,字节%d\n", pReadHeader->FrameNO, sizeof(int)*3 + sizeof(time_t) + pReadHeader->count_encode);
                result = sendto(fdsocket, &(pReadHeader->FrameNO), sizeof(int)*3 + sizeof(time_t) + pReadHeader->count_encode, 0, (struct sockaddr*)&dest_addr, socklen);
                //printf("pReadHeader->count_encode=%d, 实际发送%d字节\n", pReadHeader->count_encode, result);
                if(-1 == result)
#else
                result = sendto(fdsocket, pReadHeader->buffer_capture, sizeof(pReadHeader->buffer_capture)+sizeof(int)+sizeof(int), 0, (struct sockaddr*)&dest_addr, socklen);
                if(-1 == result)
#endif
#elif TRAN_MODE==TCP_MODE
                if(-1 == send(fdsocket, pReadHeader->buffer_capture, sizeof(pReadHeader->buffer_capture), 0))
#endif
                {
                        perror("sendto");
                }
                else
                { 
#if RECORD_SEND_PCM
                        fwrite(pReadHeader->buffer_capture, SAMPLERATE/1000*READMSFORONCE*sizeof(short), 1, fp);
#endif
                        traceprintf("n=%d\n", n);
                        //printf("    sNO:%d\n", pReadHeader->FrameNO);
                        pthread_mutex_lock(&mutex_lock);
                        pReadHeader->Valid = 0;
                        n--;
                        pthread_mutex_unlock(&mutex_lock);
                        pReadHeader = pReadHeader->pNext;
                }
        }
    }
    
    printf("数据发送线程已经关闭 data send thread is closed\n");

#if SPEEX_AUDIO_CODEC
    speex_preprocess_state_destroy(st);
#endif

#if TRAN_MODE==UDP_MODE
    close(fdsocket);
#endif

#if RECORD_SEND_PCM
    fclose(fp);
#endif

#if RECORD_ENCODE_FILE
    fclose(fp_encode);
#endif
}
Example #4
0
File: mic.c Project: naeems/bkvoice
//音频采集线程
void * capture_audio_thread(void *para)
{
    int fdsound = 0;
    int readbyte = 0;


#if RECORD_CAPTURE_PCM
    FILE *fp = fopen("capture.pcm", "wb");
#endif

#if SILK_AUDIO_CODEC
    SKP_uint8 encode[MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES];
#endif

#if SILK_AUDIO_CODEC
    init_silk_encoder();//初始化silk codec
    printf("end of init silk encoder\n");
#endif














#if (SOUND_INTERFACE == SOUND_OSS)
    fdsound = open("/dev/dsp", O_RDONLY);
    if(fdsound<0)
    {
       perror("以只写方式打开音频设备");
       //return;
    }    

    printf("设置读音频设备参数 setup capture audio device parament\n");
    ioctl(fdsound, SNDCTL_DSP_SPEED, &Frequency);//采样频率
    ioctl(fdsound, SNDCTL_DSP_SETFMT, &format);//音频设备位宽
    ioctl(fdsound, SNDCTL_DSP_CHANNELS, &channels);//音频设备通道
    ioctl(fdsound, SNDCTL_DSP_SETFRAGMENT, &setting);//采样缓冲区

    while(flag_capture_audio)
    {
        if((readbyte=read(fdsound, pWriteHeader->buffer_capture, SAMPLERATE/1000*READMSFORONCE*sizeof(short))) < 0)
        {
            perror("读声卡数据");
        }
        else
        {
            //printf("readbyte=%d\n", readbyte);
#if RECORD_CAPTURE_PCM
            fwrite(pWriteHeader->buffer_capture, SAMPLERATE/1000*READMSFORONCE*sizeof(short), 1, fp);
#endif
            traceprintf("发送信号量 sem_capture\n");
            
            pWriteHeader->FrameNO = FrameNO++;

            time(&(pWriteHeader->time));
            //printf("cNO:%d, readbyte=%d,压缩后大小%d,pWriteHeader->vad=%d\n", pWriteHeader->FrameNO, readbyte, pWriteHeader->count_encode, pWriteHeader->vad);
            pthread_mutex_lock(&mutex_lock);
            n++;
            pWriteHeader->Valid = 1;
            pthread_mutex_unlock(&mutex_lock);
            pWriteHeader = pWriteHeader->pNext;
            sem_post(&sem_capture);
        }
    }
    close(fdsound);
#elif (SOUND_INTERFACE == SOUND_ALSA)
    printf("alsa xxxxxxxxxxxxxxx\n");
    struct timeval tv;
    struct timezone tz;
    /* Open PCM device for recording (capture). */
    rc = snd_pcm_open(&handle, "plughw:0,0", SND_PCM_STREAM_CAPTURE, 0);
    if (rc < 0) 
    {
        fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
        exit(1);
    }
    snd_pcm_hw_params_alloca(&params);/* Allocate a hardware parameters object. */    
    snd_pcm_hw_params_any(handle, params);/* Fill it in with default values. */

    /* Set the desired hardware parameters. */
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);/* Interleaved mode */
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);/* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_channels(handle, params, CHANNELS);/* Two channels (stereo), On for mono */
    val = SAMPLERATE;
    snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);/* SAMPLERATE bits/second sampling rate  */
    frames = SAMPLERATE/1000*READMSFORONCE;
    snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);/* Set period size to SAMPLES_FOR_EACH_TIME frames. */

    /* Write the parameters to the driver */
    rc = snd_pcm_hw_params(handle, params);
    if (rc < 0) 
    {
        fprintf(stderr, "unable to set hw parameters: %s\n",snd_strerror(rc));
        exit(1);
    }

    snd_pcm_hw_params_get_period_size(params, &frames, &dir);/* Use a buffer large enough to hold one period */
#if 0    
    size = frames * sizeof(short) * CHANNELS; /* 2 bytes/sample, 2 channels */
    buffer = (char *) malloc(size);
#endif
    snd_pcm_hw_params_get_period_time(params, &val, &dir);/* We want to loop for 5 seconds */
                                         
    while(flag_capture_audio)
    {
        rc = snd_pcm_readi(handle, pWriteHeader->buffer_capture, frames);
        printf("read rc=%d\n", rc);
        if (rc == -EPIPE) 
        {
            /* EPIPE means overrun */
            fprintf(stderr, "overrun occurred\n");
            snd_pcm_prepare(handle);
        } 
        else if (rc < 0) 
        {
            fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
        } 
        else if (rc != (int)frames) 
        {
            fprintf(stderr, "short read, read %d frames\n", rc);
        }

#if RECORD_CAPTURE_PCM
            fwrite(pWriteHeader->buffer_capture, SAMPLERATE/1000*READMSFORONCE*sizeof(short), 1, fp);
#endif
#if 0
#if DEBUG_SAVE_CAPTURE_PCM
        rc = fwrite(pWriteHeader->buffer_capture, frames*sizeof(short), 1, fp);
        if(rc != 1)
        {
            fprintf(stderr, "write error %d\n", rc);
        }
#endif 
#endif
#if SILK_AUDIO_CODEC
            /* max payload size */
            int nbBytes = MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES;
            /* Silk Encoder */
            ret = SKP_Silk_SDK_Encode(psEnc, &encControl, pWriteHeader->buffer_capture, (SKP_int16)SAMPLERATE/1000*READMSFORONCE, pWriteHeader->buffer_encode, &nbBytes);
            pWriteHeader->count = nbBytes;
            printf("ret=%d, nbBytes=%d\n", ret, nbBytes);
            if(ret) 
            { 
                printf( "SKP_Silk_Encode returned %d, nbBytes=%d\n", ret, nbBytes);
                //break;
            }
#endif


#if SPEEX_AUDIO_CODEC
            speex_bits_reset(&bits);

            /*Encode the frame*/
            speex_encode_int(state, pWriteHeader->buffer_capture, &bits);

            /*Copy the bits to an array of char that can be written*/
            nbBytes = speex_bits_write(&bits, cbits, 200);

            printf("压缩后大小 %d\n", nbBytes);
#endif

        sem_post(&sem_capture); 
        sem_post(&sem_capture);                     
        gettimeofday(&tv, &tz);
        //((AUDIOBUFFER*)(pWriteHeader->buffer_capture))->FrameNO = FrameNO++;
        //((AUDIOBUFFER*)(pWriteHeader->buffer))->sec = tv.tv_sec;
        //((AUDIOBUFFER*)(pWriteHeader->buffer))->usec = tv.tv_usec;
        //printf("capture NO=%5d \n", FrameNO);
        pthread_mutex_lock(&mutex_lock);     
        //pWriteHeader = pWriteHeader->pNext;
        pWriteHeader->Valid = 1;
        n++;                
        pthread_mutex_unlock(&mutex_lock);  
        pWriteHeader = pWriteHeader->pNext;
        sem_post(&sem_capture);                     
        //traceprintf("发送信号量 sem_capture\n");
    }
                                         
    snd_pcm_drain(handle);
    snd_pcm_close(handle);
#if 0    
    free(buffer);
#endif  
#endif

#if RECORD_CAPTURE_PCM
    fclose(fp);
#endif

    printf("音频采集线程已经关闭 audio capture thread is closed\n");
    return NULL;
}
Example #5
0
void send_alert(activealerts_t *alert, FILE *logfd)
{
    recip_t *recip;
    int first = 1;
    int alertcount = 0;
    time_t now = getcurrenttime(NULL);
    /* A_PAGING, A_NORECIP, A_ACKED, A_RECOVERED, A_DISABLED, A_NOTIFY, A_DEAD */
    char *alerttxt[A_DEAD+1] = { "Paging", "Norecip", "Acked", "Recovered", "Disabled", "Notify", "Dead" };

    dbgprintf("send_alert %s:%s state %d\n", alert->hostname, alert->testname, (int)alert->state);
    traceprintf("send_alert %s:%s state %s\n",
                alert->hostname, alert->testname, alerttxt[alert->state]);

    stoprulefound = 0;

    while (!stoprulefound && ((recip = next_recipient(alert, &first, NULL, NULL)) != NULL)) {
        /* If this is an "UNMATCHED" rule, ignore it if we have already sent out some alert */
        if (recip->unmatchedonly && (alertcount != 0)) {
            traceprintf("Recipient '%s' dropped, not unmatched (count=%d)\n", recip->recipient, alertcount);
            continue;
        }

        if (recip->noalerts && ((alert->state == A_PAGING) || (alert->state == A_RECOVERED) || (alert->state == A_DISABLED))) {
            traceprintf("Recipient '%s' dropped (NOALERT)\n", recip->recipient);
            continue;
        }

        if (recip->method == M_IGNORE) {
            traceprintf("IGNORE rule found\n");
            continue;
        }

        if (alert->state == A_PAGING) {
            repeat_t *rpt = NULL;

            /*
             * This runs in a child-process context, so the record we
             * might create here is NOT used later on.
             */
            rpt = find_repeatinfo(alert, recip, 1);
            if (!rpt) continue;	/* Happens for e.g. M_IGNORE recipients */

            dbgprintf("  repeat %s at %d\n", rpt->recipid, rpt->nextalert);
            if (rpt->nextalert > now) {
                traceprintf("Recipient '%s' dropped, next alert due at %ld > %ld\n",
                            rpt->recipid, (long)rpt->nextalert, (long)now);
                continue;
            }
            alertcount++;
        }
        else if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) {
            /* RECOVERED messages require that we've sent out an alert before */
            repeat_t *rpt = NULL;

            rpt = find_repeatinfo(alert, recip, 0);
            if (!rpt) continue;
            alertcount++;
        }

        dbgprintf("  Alert for %s:%s to %s\n", alert->hostname, alert->testname, recip->recipient);
        switch (recip->method) {
        case M_IGNORE:
            break;

        case M_MAIL:
        {
            char cmd[32768];
            char *mailsubj;
            char *mailrecip;
            FILE *mailpipe;

            MEMDEFINE(cmd);

            mailsubj = message_subject(alert, recip);
            mailrecip = message_recipient(recip->recipient, alert->hostname, alert->testname, colorname(alert->color));

            if (mailsubj) {
                if (xgetenv("MAIL"))
                    sprintf(cmd, "%s \"%s\" ", xgetenv("MAIL"), mailsubj);
                else if (xgetenv("MAILC"))
                    sprintf(cmd, "%s -s \"%s\" ", xgetenv("MAILC"), mailsubj);
                else
                    sprintf(cmd, "mail -s \"%s\" ", mailsubj);
            }
            else {
                if (xgetenv("MAILC"))
                    sprintf(cmd, "%s ", xgetenv("MAILC"));
                else
                    sprintf(cmd, "mail ");
            }
            strcat(cmd, mailrecip);

            traceprintf("Mail alert with command '%s'\n", cmd);
            if (testonly) {
                MEMUNDEFINE(cmd);
                break;
            }

            mailpipe = popen(cmd, "w");
            if (mailpipe) {
                fprintf(mailpipe, "%s", message_text(alert, recip));
                pclose(mailpipe);
                if (logfd) {
                    init_timestamp();
                    fprintf(logfd, "%s %s.%s (%s) %s[%d] %ld %d",
                            timestamp, alert->hostname, alert->testname,
                            alert->ip, mailrecip, recip->cfid,
                            (long)now, servicecode(alert->testname));
                    if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) {
                        fprintf(logfd, " %ld\n", (long)(now - alert->eventstart));
                    }
                    else {
                        fprintf(logfd, "\n");
                    }
                    fflush(logfd);
                }
            }
            else {
                errprintf("ERROR: Cannot open command pipe for '%s' - alert lost!\n", cmd);
                traceprintf("Mail pipe failed - alert lost\n");
            }

            MEMUNDEFINE(cmd);
        }
        break;

        case M_SCRIPT:
        {
            pid_t scriptpid;
            char *scriptrecip;

            traceprintf("Script alert with command '%s' and recipient %s\n", recip->scriptname, recip->recipient);
            if (testonly) break;

            scriptrecip = message_recipient(recip->recipient, alert->hostname, alert->testname, colorname(alert->color));
            scriptpid = fork();
            if (scriptpid == 0) {
                /* Setup all of the environment for a paging script */
                void *hinfo;
                char *p;
                int ip1=0, ip2=0, ip3=0, ip4=0;
                char *bbalphamsg, *ackcode, *rcpt, *bbhostname, *bbhostsvc, *bbhostsvccommas, *bbnumeric, *machip, *bbsvcname, *bbsvcnum, *bbcolorlevel, *recovered, *downsecs, *eventtstamp, *downsecsmsg, *cfidtxt;
                char *alertid, *alertidenv;
                int msglen;

                cfidtxt = (char *)malloc(strlen("CFID=") + 10);
                sprintf(cfidtxt, "CFID=%d", recip->cfid);
                putenv(cfidtxt);

                p = message_text(alert, recip);
                msglen = strlen(p);
                if (msglen > MAX_ALERTMSG_SCRIPTS) {
                    dbgprintf("Cropping large alert message from %d to %d bytes\n", msglen, MAX_ALERTMSG_SCRIPTS);
                    msglen = MAX_ALERTMSG_SCRIPTS;
                }
                msglen += strlen("BBALPHAMSG=");
                bbalphamsg = (char *)malloc(msglen + 1);
                snprintf(bbalphamsg, msglen+1, "BBALPHAMSG=%s", p);
                putenv(bbalphamsg);

                ackcode = (char *)malloc(strlen("ACKCODE=") + 10);
                sprintf(ackcode, "ACKCODE=%d", alert->cookie);
                putenv(ackcode);

                rcpt = (char *)malloc(strlen("RCPT=") + strlen(scriptrecip) + 1);
                sprintf(rcpt, "RCPT=%s", scriptrecip);
                putenv(rcpt);

                bbhostname = (char *)malloc(strlen("BBHOSTNAME=") + strlen(alert->hostname) + 1);
                sprintf(bbhostname, "BBHOSTNAME=%s", alert->hostname);
                putenv(bbhostname);

                bbhostsvc = (char *)malloc(strlen("BBHOSTSVC=") + strlen(alert->hostname) + 1 + strlen(alert->testname) + 1);
                sprintf(bbhostsvc, "BBHOSTSVC=%s.%s", alert->hostname, alert->testname);
                putenv(bbhostsvc);

                bbhostsvccommas = (char *)malloc(strlen("BBHOSTSVCCOMMAS=") + strlen(alert->hostname) + 1 + strlen(alert->testname) + 1);
                sprintf(bbhostsvccommas, "BBHOSTSVCCOMMAS=%s.%s", commafy(alert->hostname), alert->testname);
                putenv(bbhostsvccommas);

                bbnumeric = (char *)malloc(strlen("BBNUMERIC=") + 22 + 1);
                p = bbnumeric;
                p += sprintf(p, "BBNUMERIC=");
                p += sprintf(p, "%03d", servicecode(alert->testname));
                sscanf(alert->ip, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
                p += sprintf(p, "%03d%03d%03d%03d", ip1, ip2, ip3, ip4);
                p += sprintf(p, "%d", alert->cookie);
                putenv(bbnumeric);

                machip = (char *)malloc(strlen("MACHIP=") + 13);
                sprintf(machip, "MACHIP=%03d%03d%03d%03d", ip1, ip2, ip3, ip4);
                putenv(machip);

                bbsvcname = (char *)malloc(strlen("BBSVCNAME=") + strlen(alert->testname) + 1);
                sprintf(bbsvcname, "BBSVCNAME=%s", alert->testname);
                putenv(bbsvcname);

                bbsvcnum = (char *)malloc(strlen("BBSVCNUM=") + 10);
                sprintf(bbsvcnum, "BBSVCNUM=%d", servicecode(alert->testname));
                putenv(bbsvcnum);

                bbcolorlevel = (char *)malloc(strlen("BBCOLORLEVEL=") + strlen(colorname(alert->color)) + 1);
                sprintf(bbcolorlevel, "BBCOLORLEVEL=%s", colorname(alert->color));
                putenv(bbcolorlevel);

                recovered = (char *)malloc(strlen("RECOVERED=") + 2);
                switch (alert->state) {
                case A_RECOVERED:
                    strcpy(recovered, "RECOVERED=1");
                    break;
                case A_DISABLED:
                    strcpy(recovered, "RECOVERED=2");
                    break;
                default:
                    strcpy(recovered, "RECOVERED=0");
                    break;
                }
                putenv(recovered);

                downsecs = (char *)malloc(strlen("DOWNSECS=") + 20);
                sprintf(downsecs, "DOWNSECS=%ld", (long)(getcurrenttime(NULL) - alert->eventstart));
                putenv(downsecs);

                eventtstamp = (char *)malloc(strlen("EVENTSTART=") + 20);
                sprintf(eventtstamp, "EVENTSTART=%ld", (long)alert->eventstart);
                putenv(eventtstamp);

                if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) {
                    downsecsmsg = (char *)malloc(strlen("DOWNSECSMSG=Event duration :") + 20);
                    sprintf(downsecsmsg, "DOWNSECSMSG=Event duration : %ld", (long)(getcurrenttime(NULL) - alert->eventstart));
                }
                else {
                    downsecsmsg = strdup("DOWNSECSMSG=");
                }
                putenv(downsecsmsg);

                alertid = make_alertid(alert->hostname, alert->testname, alert->eventstart);
                alertidenv = (char *)malloc(strlen("ALERTID=") + strlen(alertid) + 10);
                sprintf(alertidenv, "ALERTID=%s", alertid);
                putenv(alertidenv);

                hinfo = hostinfo(alert->hostname);
                if (hinfo) {
                    enum xmh_item_t walk;
                    char *itm, *id, *bbhenv;

                    for (walk = 0; (walk < XMH_LAST); walk++) {
                        itm = xmh_item(hinfo, walk);
                        id = xmh_item_id(walk);
                        if (itm && id) {
                            bbhenv = (char *)malloc(strlen(id) + strlen(itm) + 2);
                            sprintf(bbhenv, "%s=%s", id, itm);
                            putenv(bbhenv);
                        }
                    }
                }

                /* The child starts the script */
                execlp(recip->scriptname, recip->scriptname, NULL);
                errprintf("Could not launch paging script %s: %s\n",
                          recip->scriptname, strerror(errno));
                exit(0);
            }
            else if (scriptpid > 0) {
                /* Parent waits for child to complete */
                int childstat;

                wait(&childstat);
                if (WIFEXITED(childstat) && (WEXITSTATUS(childstat) != 0)) {
                    errprintf("Paging script %s terminated with status %d\n",
                              recip->scriptname, WEXITSTATUS(childstat));
                }
                else if (WIFSIGNALED(childstat)) {
                    errprintf("Paging script %s terminated by signal %d\n",
                              recip->scriptname, WTERMSIG(childstat));
                }

                if (logfd) {
                    init_timestamp();
                    fprintf(logfd, "%s %s.%s (%s) %s %ld %d",
                            timestamp, alert->hostname, alert->testname,
                            alert->ip, scriptrecip, (long)now,
                            servicecode(alert->testname));
                    if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) {
                        fprintf(logfd, " %ld\n", (long)(now - alert->eventstart));
                    }
                    else {
                        fprintf(logfd, "\n");
                    }
                    fflush(logfd);
                }
            }
            else {
                errprintf("ERROR: Fork failed to launch script '%s' - alert lost\n", recip->scriptname);
                traceprintf("Script fork failed - alert lost\n");
            }
        }
        break;
        }
    }
}
Example #6
0
static int criteriamatch(activealerts_t *alert, criteria_t *crit, criteria_t *rulecrit, int *anymatch, time_t *nexttime)
{
	/*
	 * See if the "crit" matches the "alert".
	 * Match on pagespec, dgspec, hostspec, svcspec, classspec, groupspec, colors, timespec, minduration, maxduration, sendrecovered
	 */

	static char *pgnames = NULL;
	int pgmatchres, pgexclres;
	time_t duration = (getcurrenttime(NULL) - alert->eventstart);
	int result, cfid = 0;
	char *pgtok, *cfline = NULL;
	void *hinfo = hostinfo(alert->hostname);

	/* The top-level page needs a name - cannot match against an empty string */
	if (pgnames) xfree(pgnames);
	pgnames = strdup((*alert->location == '\0') ? "/" : alert->location);

	if (crit) { cfid = crit->cfid; cfline = crit->cfline; }
	if (!cfid && rulecrit) cfid = rulecrit->cfid;
	if (!cfline && rulecrit) cfline = rulecrit->cfline;
	if (!cfline) cfline = "<undefined>";

	traceprintf("Matching host:service:dgroup:page '%s:%s:%s:%s' against rule line %d\n",
			alert->hostname, alert->testname, xmh_item(hinfo, XMH_DGNAME), alert->location, cfid);

	if (alert->state == A_PAGING) {
		/* Check max-duration now - it's fast and easy. */
		if (crit && crit->maxduration && (duration > crit->maxduration)) { 
			traceprintf("Failed '%s' (max. duration %d>%d)\n", cfline, duration, crit->maxduration);
			if (!printmode) return 0; 
		}
	}

	if (crit && crit->classspec && !namematch(alert->classname, crit->classspec, crit->classspecre)) { 
		traceprintf("Failed '%s' (class not in include list)\n", cfline);
		return 0; 
	}
	if (crit && crit->exclassspec && namematch(alert->classname, crit->exclassspec, crit->exclassspecre)) { 
		traceprintf("Failed '%s' (class excluded)\n", cfline);
		return 0; 
	}

	/* alert->groups is a comma-separated list of groups, so it needs some special handling */
	/* 
	 * NB: Dont check groups when RECOVERED - the group list for recovery messages is always empty.
	 * It doesn't matter if we match a recipient who was not in the group that originally
	 * got the alert - we will later check who has received the alert, and only those that
	 * have will get the recovery message.
	 */
	if (crit && (crit->groupspec || crit->exgroupspec) && (alert->state != A_RECOVERED)) {
		char *grouplist;
		char *tokptr;

		grouplist = (alert->groups && (*(alert->groups))) ? strdup(alert->groups) : NULL;
		if (crit->groupspec) {
			char *onegroup;
			int iswanted = 0;

			if (grouplist) {
				/* There is a group label on the alert, so it must match */
				onegroup = strtok_r(grouplist, ",", &tokptr);
				while (onegroup && !iswanted) {
					iswanted = (namematch(onegroup, crit->groupspec, crit->groupspecre));
					onegroup = strtok_r(NULL, ",", &tokptr);
				}
			}

			if (!iswanted) {
				/*
				 * Either the alert had a group list that didn't match, or
				 * there was no group list and the rule listed one.
				 * In both cases, it's a failed match.
				 */
				traceprintf("Failed '%s' (group not in include list)\n", cfline);
				if (grouplist) xfree(grouplist);
				return 0; 
			}
		}

		if (crit->exgroupspec && grouplist) {
			char *onegroup;

			/* Excluded groups are only handled when the alert does have a group list */

			strcpy(grouplist, alert->groups); /* Might have been used in the include list */
			onegroup = strtok_r(grouplist, ",", &tokptr);
			while (onegroup) {
				if (namematch(onegroup, crit->exgroupspec, crit->exgroupspecre)) { 
					traceprintf("Failed '%s' (group excluded)\n", cfline);
					xfree(grouplist);
					return 0; 
				}
				onegroup = strtok_r(NULL, ",", &tokptr);
			}
		}

		if (grouplist) xfree(grouplist);
	}

	pgmatchres = pgexclres = -1;
	pgtok = strtok(pgnames, ",");
	while (pgtok) {
		if (crit && crit->pagespec && (pgmatchres != 1))
			pgmatchres = (namematch(pgtok, crit->pagespec, crit->pagespecre) ? 1 : 0);

		if (crit && crit->expagespec && (pgexclres != 1))
			pgexclres = (namematch(pgtok, crit->expagespec, crit->expagespecre) ? 1 : 0);

		pgtok = strtok(NULL, ",");
	}
	if (pgexclres == 1) {
		traceprintf("Failed '%s' (pagename excluded)\n", cfline);
		return 0; 
	}
	if (pgmatchres == 0) {
		traceprintf("Failed '%s' (pagename not in include list)\n", cfline);
		return 0;
	}

	if (crit && crit->dgspec && !namematch(xmh_item(hinfo, XMH_DGNAME), crit->dgspec, crit->dgspecre)) { 
		traceprintf("Failed '%s' (displaygroup not in include list)\n", cfline);
		return 0; 
	}
	if (crit && crit->exdgspec && namematch(xmh_item(hinfo, XMH_DGNAME), crit->exdgspec, crit->exdgspecre)) { 
		traceprintf("Failed '%s' (displaygroup excluded)\n", cfline);
		return 0; 
	}

	if (crit && crit->hostspec && !namematch(alert->hostname, crit->hostspec, crit->hostspecre)) { 
		traceprintf("Failed '%s' (hostname not in include list)\n", cfline);
		return 0; 
	}
	if (crit && crit->exhostspec && namematch(alert->hostname, crit->exhostspec, crit->exhostspecre)) { 
		traceprintf("Failed '%s' (hostname excluded)\n", cfline);
		return 0; 
	}

	if (crit && crit->svcspec && !namematch(alert->testname, crit->svcspec, crit->svcspecre))  { 
		traceprintf("Failed '%s' (service not in include list)\n", cfline);
		return 0; 
	}
	if (crit && crit->exsvcspec && namematch(alert->testname, crit->exsvcspec, crit->exsvcspecre))  { 
		traceprintf("Failed '%s' (service excluded)\n", cfline);
		return 0; 
	}

	if (alert->state == A_NOTIFY) {
		/*
		 * Dont do the check until we are checking individual recipients (rulecrit is set).
		 * You dont need to have NOTICE on the top-level rule, it's enough if a recipient
		 * has it set. However, we do want to allow there to be a default defined in the
		 * rule; but it doesn't take effect until we start checking the recipients.
		 */
		if (rulecrit) {
			int n = (crit ? crit->sendnotice : -1);
			traceprintf("Checking NOTICE setting %d (rule:%d)\n", n, rulecrit->sendnotice);
			if (crit && (crit->sendnotice == SR_NOTWANTED)) result = 0;	/* Explicit NONOTICE */
			else if (crit && (crit->sendnotice == SR_WANTED)) result = 1;	/* Explicit NOTICE */
			else result = (rulecrit->sendnotice == SR_WANTED);		/* Not set, but rule has NOTICE */
		}
		else {
			result = 1;
		}

		if (!result) traceprintf("Failed '%s' (notice not wanted)\n", cfline);
		return result;
	}

	/* At this point, we know the configuration may result in an alert. */
	if (anymatch) (*anymatch)++;

	/* 
	 * Duration checks should be done on real paging messages only. 
	 * Not on recovery- or notify-messages.
	 */
	if (alert->state == A_PAGING) {
		if (crit && crit->minduration && (duration < crit->minduration)) { 
			if (nexttime) {
				time_t mynext = alert->eventstart + crit->minduration;

				if ((*nexttime == -1) || (*nexttime > mynext)) *nexttime = mynext;
			}
			traceprintf("Failed '%s' (min. duration %d<%d)\n", cfline, duration, crit->minduration);
			if (!printmode) return 0; 
		}
	}

	/*
	 * Time restrictions apply to ALL messages.
	 * Before 4.2, these were only applied to ALERT messages,
	 * not RECOVERED and NOTIFY messages. This caused some
	 * unfortunate alerts in the middle of the night because
	 * some random system recovered ... not good. So apply
	 * this check to all messages.
	 */
	if (crit && crit->timespec && !timematch(xmh_item(hinfo, XMH_HOLIDAYS), crit->timespec)) {
		traceprintf("Failed '%s' (time criteria)\n", cfline);
		if (!printmode) return 0; 
	}

	/* Check color. For RECOVERED messages, this holds the color of the alert, not the recovery state */
	if (crit && crit->colors) {
		result = (((1 << alert->color) & crit->colors) != 0);
		if (printmode) return 1;
	}
	else {
		result = (((1 << alert->color) & defaultcolors) != 0);
		if (printmode) return 1;
	}
	if (!result) {
		traceprintf("Failed '%s' (color)\n", cfline);
		return result;
	}

	if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) {
		/*
		 * Dont do the check until we are checking individual recipients (rulecrit is set).
		 * You dont need to have RECOVERED on the top-level rule, it's enough if a recipient
		 * has it set. However, we do want to allow there to be a default defined in the
		 * rule; but it doesn't take effect until we start checking the recipients.
		 */
		if (rulecrit) {
			int n = (crit ? crit->sendrecovered : -1);
			traceprintf("Checking recovered setting %d (rule:%d)\n", n, rulecrit->sendrecovered);
			if (crit && (crit->sendrecovered == SR_NOTWANTED)) result = 0;		/* Explicit NORECOVERED */
			else if (crit && (crit->sendrecovered == SR_WANTED)) result = 1;	/* Explicit RECOVERED */
			else result = (rulecrit->sendrecovered == SR_WANTED);	/* Not set, but rule has RECOVERED */
		}
		else {
			result = 1;
		}

		if (printmode) return result;
	}

	if (result) {
		traceprintf("*** Match with '%s' ***\n", cfline);
	}

	return result;
}