Example #1
0
File: ifutil.c Project: aosm/bootp
PRIVATE_EXTERN int
inet6_linklocal_start(const char * ifname, boolean_t use_cga)
{
    int ret = 0;
    int s = inet6_dgram_socket();

    if (s < 0) {
	ret = errno;
	my_log(LOG_ERR, 
	       "inet6_linklocal_start(%s): socket() failed, %s (%d)",
	       ifname, strerror(ret), ret);
	goto done;
    }
    nd_flags_set_with_socket(s, ifname, 0, ND6_IFF_IFDISABLED);
    if (ll_start(s, ifname, use_cga) < 0) {
	ret = errno;
	if (errno != ENXIO) {
	    my_log(LOG_ERR, "siocll_start(%s) failed, %s (%d)",
		   ifname, strerror(errno), errno);
	}
    }
    close(s);
 done:
    return (ret);
}
Example #2
0
//-----------------------------------------------------------------------------
// Look in the internal params list and return the value if the name exists.  
// If the name doesnt exist, then return NULL.
const char * rq_http_param(rq_http_req_t *req, char *name)
{
	param_t *param;
	char *value = NULL;
	
	assert(req);
	assert(name);
	
	if(req->param_list) {
		ll_start(req->param_list);
		param = ll_next(req->param_list);
		while (param) {
			assert(param->key);
			assert(param->value);
			if (strcmp(param->key, name) == 0) {
				value = param->value;
				param = NULL;
			}
			else {
				param = ll_next(req->param_list);
			}
		}
		ll_finish(req->param_list);
	}
	
	return(value);
}
void ChunkTable::emit(FILE *fp)
{
	LinkedListIterator lli;
	for (ll_start(&chunks, &lli); ll_has_more(&lli); ll_advance(&lli))
	{
		ChunkEntry *chunk = (ChunkEntry *) ll_read(&lli);
		ZF_Chdr *chdr = chunk->get_chdr();
		int rc = fwrite((uint8_t*) chdr, sizeof(*chdr), 1, fp);
		lite_assert(rc==1);
	}
}
Example #4
0
File: signals.c Project: hyper/rq
void sighup_handler(evutil_socket_t fd, short what, void *arg)
{
	system_data_t *sysdata = (system_data_t *) arg;
	expbuf_t *buf;
	queue_t *q;
	
	assert(sysdata);
	assert(sysdata->bufpool);
	buf = expbuf_pool_new(sysdata->bufpool, 1024);

	expbuf_print(buf, "Complete data dump\n");

	assert(sysdata->msg_list);
	expbuf_print(buf, "Messages:\n\tMax=%d\n\tActive=%d\n\n", sysdata->msg_max, sysdata->msg_used);

	assert(sysdata->in_buf);
	assert(sysdata->build_buf);
	expbuf_print(buf, "In Buffer size: %d\n", BUF_MAX(sysdata->in_buf));
	expbuf_print(buf, "Build Buffer size: %d\n", BUF_MAX(sysdata->build_buf));

	expbuf_print(buf, "\nEvents:\n");
	expbuf_print(buf, "\tsigint: %s\n",  sysdata->sigint_event  ? "yes" : "no");
	expbuf_print(buf, "\tsighup: %s\n",  sysdata->sighup_event  ? "yes" : "no");
	expbuf_print(buf, "\tsigusr1: %s\n", sysdata->sigusr1_event ? "yes" : "no");
	expbuf_print(buf, "\tsigusr2: %s\n", sysdata->sigusr2_event ? "yes" : "no");

// 	list_t *servers;

// 	list_t *controllers;

// 	list_t *nodelist;

	expbuf_print(buf, "\nQueues:\n");
	assert(sysdata->queues);
	ll_start(sysdata->queues);
	while ((q = ll_next(sysdata->queues))) {
		queue_dump(q, buf);
	}
	ll_finish(sysdata->queues);


	assert(sysdata->logging);
	expbuf_print(buf, "\nLogging:\n");
	expbuf_print(buf, "\tLog Level: %d\n", log_getlevel(sysdata->logging));
  expbuf_print(buf, "\tDump string length: ");
	expbuf_print(buf, "%d\n", BUF_LENGTH(buf));

	logger(sysdata->logging, 1, "%s", expbuf_string(buf));
	expbuf_clear(buf);

	// return the buffer to the pool.
	expbuf_pool_return(sysdata->bufpool, buf);
}
XVFSMount *XVFSNamespace::lookup(XfsPath *path)
{
	LinkedListIterator lli;
	for (ll_start(&mounts, &lli); ll_has_more(&lli); ll_advance(&lli))
	{
		XVFSMount *mount = (XVFSMount *) ll_read(&lli);
		if (_prefix_match(path->pathstr, mount->prefix))
		{
			path->suffix = path->pathstr + lite_strlen(mount->prefix);
			return mount;
		}
	}
	return NULL;
}
Example #6
0
// This callback function is called when the CMD_EXECUTE command is received.  
// It should look at the data received so far, and figure out what operation 
// needs to be done on that data.
static void cmdCheck(control_t *ptr)
{
	entry_t *entry;
	int status = 0;
	
 	assert(ptr);

	if (ptr->ip != 0) {
		assert(ptr->entries);
	 	assert(ptr->req);
	 	assert(ptr->reply);

	 	ll_start(ptr->entries);
	 	entry = ll_next(ptr->entries);
	 	while (entry) {
			assert(entry->start != 0 && entry->end != 0);
			assert(entry->end >= entry->start);

			// the entries are sorted, so if the entry is greater than what we are looking for, then it is not here.
			assert(status == 0);
			if (entry->start > ptr->ip) {
				entry = NULL;
			}
			else if (ptr->ip >= entry->start && ptr->ip <= entry->end) {
				status = 1;
				entry = NULL;
		 	}
		 	else {
			 	entry = ll_next(ptr->entries);
			}
	 	}
	 	ll_finish(ptr->entries);
	}
	assert(status == 0 || status == 1);

	assert(ptr->reply);
	assert(BUF_LENGTH(ptr->reply) == 0);
	if (status == 0) {
		// ip is not blocked.
		addCmd(ptr->reply, BL_CMD_CLEAR);
		addCmd(ptr->reply, BL_CMD_ACCEPT);
	}
	else {
		// ip is blocked.
		addCmd(ptr->reply, BL_CMD_CLEAR);
		addCmd(ptr->reply, BL_CMD_DENY);
	}
}
void MmapDecoder::_dbg_dump_foreach(void* v_this, void* v_behavior)
{
	MmapBehavior* behavior = (MmapBehavior*) v_behavior;
	fprintf(stderr, "%s: aligned_mapping_size %x x %d\n",
		behavior->filename,
		behavior->aligned_mapping_size,
		behavior->aligned_mapping_copies);
	
	LinkedListIterator lli;
	for (ll_start(&behavior->precious_ranges, &lli);
		ll_has_more(&lli);
		ll_advance(&lli))
	{
		MDRange* range = (MDRange*) ll_read(&lli);
		fprintf(stderr, "  range %x--%x\n", range->start, range->end);
	}
}
Example #8
0
int
os_ll_start(perf_ctl_t *ctl, perf_task_t *task)
{
	os_allstop();
	proc_callchain_clear();
	proc_profiling_clear();
	node_profiling_clear();

	if (ll_start(ctl) != 0) {
		/*
		 * It could be failed if the kernel doesn't support PEBS LL.
		 */
		debug_print(NULL, 2, "ll_start is failed\n");
		perf_status_set(PERF_STATUS_LL_FAILED);
		return (-1);
	}

	debug_print(NULL, 2, "ll_start success\n");
	perf_status_set(PERF_STATUS_LL_STARTED);
	return (0);
}
void MmapBehavior::insert_range(MDRange* a_range)
{
	bool matches_existing = false;

	LinkedListIterator lli;
	for (ll_start(&precious_ranges, &lli);
		ll_has_more(&lli);
		ll_advance(&lli))
	{
		MDRange* range = (MDRange*) ll_read(&lli);
		if (range->includes(*a_range))
		{
			matches_existing = true;
			break;
		}
	}
	// TODO not very precise; doesn't coalesce ranges or anything. But
	// seems adequate.
	if (!matches_existing)
	{
		MDRange *new_range = new MDRange(*a_range);
		linked_list_insert_tail(&precious_ranges, new_range);
	}
}
Example #10
0
//-----------------------------------------------------------------------------
// make a blacklist query and call the handler function when we have an answer.
// 
// NOTE: that it is possible for the callback funcction to be called before
//       this function exits (if the result is already cached), so dont put
//       any important initialization of the passed in object after this call
//       is made.
rq_blacklist_id_t rq_blacklist_check(
	rq_blacklist_t *blacklist,
	struct sockaddr *address,
	int socklen,
	void (*handler)(rq_blacklist_status_t status, void *arg), void *arg)
{
	struct sockaddr_in *sin;
	ev_uint32_t ip;
	cache_entry_t *entry;
	struct timeval tv;
	time_t curtime;
	rq_message_t *msg;
	cache_waiting_t *waiting;
	rq_blacklist_id_t id;

	assert(blacklist);
	assert(address);
	assert(socklen > 0);
	assert(handler);
	assert(arg);

	// convert 'address' into a 32bit uint.
	sin = (struct sockaddr_in *) address;
	ip = sin->sin_addr.s_addr;

	// get the current time in seconds.
	gettimeofday(&tv, NULL);
	curtime=tv.tv_sec;

	// check the cache for the address.
	assert(blacklist->cache);
	ll_start(blacklist->cache);
	entry = ll_next(blacklist->cache);
	while (entry) {
		if (entry->ip == ip) {
			// check to see if entry has expired.
			assert(entry->expires > 0);
			if (entry->expires <= curtime) {
				// cached entry has expired, so we need to remove it from the list.
				ll_remove(blacklist->cache, entry);
				free(entry);
			}
			else {
				// entry is in the list, so we call the handler, and then we return 0.
				handler(entry->status, arg);
				ll_finish(blacklist->cache);
				return(0);
			}
			entry = NULL;
		}
		else {
			entry = ll_next(blacklist->cache);
		}
	}
	ll_finish(blacklist->cache);
	
	// if we got this far, then the entry was not found in the cache, so we need
	// to send a request to the queue.

	// get the next id.
	id = next_id(blacklist);

	// create the structure that will hold the information we are waiting on, and add it to the tail of the list.
	waiting = (cache_waiting_t *)  malloc(sizeof(cache_waiting_t));
	assert(waiting);
	waiting->id = id;
	waiting->ip = ip;
	waiting->arg = arg;
	waiting->blacklist = blacklist;
	waiting->msg = NULL;
	waiting->handler = handler;
	ll_push_tail(blacklist->waiting, waiting);

	// now create a message object so we can send the message
	assert(blacklist->queue);
	assert(blacklist->rq);
	msg = rq_msg_new(blacklist->rq, NULL);
	assert(msg);
	assert(msg->data);

	// apply the queue that we are sending a request for.
	rq_msg_setqueue(msg, blacklist->queue);

	// build the command payload.
	rq_msg_addcmd(msg, BL_CMD_CLEAR);
// 	rq_msg_addcmd(msg, BL_CMD_NOP);
	rq_msg_addcmd_largeint(msg, BL_CMD_IP, ip);
	rq_msg_addcmd(msg, BL_CMD_CHECK);

	// message has been prepared, so send it.
	// TODO: add fail handler.
	rq_send(msg, blacklist_handler, NULL, waiting);
	msg = NULL;

	return(id);
}
void corefile_write_custom(CoreFile *c, write_callback_func *write_func, tell_callback_func *ftell_func, void *user_file_obj)
{
//	write_func(user_file_obj, "slicksnot", 9);
	const int num_notes = 1;
	int pad_i;
	int hdr_offset = 0;
	bool rc;
	Elf32_Ehdr ehdr;

	int thread_notes_size = c->threads.count * sizeof(CoreNote_Regs);

	// compute how much header space we need...
	int hdr_size = 0
		+sizeof(Elf32_Ehdr)
		+sizeof(Elf32_Phdr)					// NOTE hdr
		+sizeof(Elf32_Phdr)*c->segments.count
		+thread_notes_size
		+sizeof(c->corenote_zoog);
	int rounded_hdr_size = (hdr_size + 0xfff) & ~0xfff;
	int pad_size = rounded_hdr_size - hdr_size;

	// ...so that we can plan on laying data segments down after that.
	int seg_file_offset = rounded_hdr_size;

	ehdr.e_ident[EI_MAG0] = ELFMAG0;
	ehdr.e_ident[EI_MAG1] = ELFMAG1;
	ehdr.e_ident[EI_MAG2] = ELFMAG2;
	ehdr.e_ident[EI_MAG3] = ELFMAG3;
	ehdr.e_ident[EI_CLASS] = ELFCLASS32;
	ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
	ehdr.e_ident[EI_VERSION] = EV_CURRENT;
	ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE;
	ehdr.e_ident[EI_ABIVERSION] = 0;

	for (pad_i=EI_PAD; pad_i<EI_NIDENT; pad_i++)
	{
		ehdr.e_ident[pad_i] = 0;
	}
	ehdr.e_type = ET_CORE;
	ehdr.e_machine = EM_386;
	ehdr.e_version = EV_CURRENT;
	ehdr.e_entry = 0;
	ehdr.e_phoff = sizeof(ehdr);
	ehdr.e_shoff = 0;
	ehdr.e_flags = 0;
	ehdr.e_ehsize = sizeof(ehdr);
	ehdr.e_phentsize = sizeof(Elf32_Phdr);
	ehdr.e_phnum = (Elf32_Half) (num_notes + c->segments.count);
	ehdr.e_shentsize = 0;
	ehdr.e_shnum = 0;
	ehdr.e_shstrndx = 0;

	rc = write_func(user_file_obj, &ehdr, sizeof(ehdr));
	lite_assert(rc);
	hdr_offset += sizeof(ehdr);

	// write CoreNotes Phdr
	{
		lite_assert(c->corenote_zoog.bootblock_addr != 0x0);

		Elf32_Phdr phdr;
		phdr.p_type = PT_NOTE;
		phdr.p_flags = 0;
		phdr.p_offset = hdr_offset + sizeof(Elf32_Phdr)*ehdr.e_phnum;
		phdr.p_vaddr = 0;
		phdr.p_paddr = 0;
		phdr.p_filesz = thread_notes_size + sizeof(c->corenote_zoog);
		phdr.p_memsz = 0;
		phdr.p_align = 0;

		rc = (*write_func)(user_file_obj, &phdr, sizeof(phdr));
		lite_assert(rc);
		hdr_offset += sizeof(phdr);
	}

	LinkedListIterator lli;
	for (ll_start(&c->segments, &lli);
		ll_has_more(&lli);
		ll_advance(&lli))
	{
		CoreSegment *seg = (CoreSegment *) ll_read(&lli);

		Elf32_Phdr phdr;
		lite_assert((seg->size & 0xfff) == 0);

		phdr.p_type = PT_LOAD;
		phdr.p_flags = PF_X|PF_W|PF_R;
		phdr.p_offset = seg_file_offset;
		phdr.p_vaddr = (uint32_t) seg->vaddr;
		phdr.p_paddr = 0;
		phdr.p_filesz = seg->size;
		phdr.p_memsz = seg->size;
		phdr.p_align = 0x1000;

		rc = (*write_func)(user_file_obj, &phdr, sizeof(phdr));
		lite_assert(rc);
		hdr_offset += sizeof(phdr);

		seg_file_offset += phdr.p_filesz;
		lite_assert(ftell_func==NULL || hdr_offset == (*ftell_func)(user_file_obj));
	}

	// write the PT_NOTEs that contains the register & zoog symbol info
	{
		LinkedListIterator lli;
		for (ll_start(&c->threads, &lli);
			ll_has_more(&lli);
			ll_advance(&lli))
		{
			CoreNote_Regs *corenote_regs = (CoreNote_Regs *) ll_read(&lli);

			rc = (*write_func)(user_file_obj, corenote_regs, sizeof(*corenote_regs));
			lite_assert(rc);
			hdr_offset += sizeof(*corenote_regs);
		}
		rc = (*write_func)(user_file_obj, &c->corenote_zoog, sizeof(c->corenote_zoog));
		lite_assert(rc);
		hdr_offset += sizeof(c->corenote_zoog);
	}

	lite_assert(pad_size>=0);

	lite_assert(pad_size < 0x1000);
	char pad_zeros[0x1000];
	lite_memset(pad_zeros, 0, sizeof(pad_zeros));
	rc = (*write_func)(user_file_obj, &pad_zeros, pad_size);
	lite_assert(rc);
	lite_assert(ftell_func==NULL || rounded_hdr_size == (*ftell_func)(user_file_obj));
	seg_file_offset = rounded_hdr_size;

	for (ll_start(&c->segments, &lli);
		ll_has_more(&lli);
		ll_advance(&lli))
	{
		CoreSegment *seg = (CoreSegment *) ll_read(&lli);

		rc = (*write_func)(user_file_obj, seg->bytes, seg->size);
		lite_assert(rc);
		seg_file_offset += seg->size;
		lite_assert(ftell_func==NULL || seg_file_offset == (*ftell_func)(user_file_obj));
	}
}
Example #12
0
//-----------------------------------------------------------------------------
// callback function that will fire when the connection to the controller is reached.
static void controller_connect_handler(int fd, short int flags, void *arg)
{
	controller_t *ct = (controller_t *) arg;
	node_t *node;
	system_data_t *sysdata;
	queue_t *q;
	int error;
	socklen_t foo;
	struct timeval t = {.tv_sec = 1, .tv_usec = 0};
	short int exclusive;

	assert(fd >= 0);
	assert(flags != 0);
	assert(ct);
	assert(ct->node == NULL);
	assert(ct->target);
	assert(ct->sysdata);
	sysdata = ct->sysdata;
	
	// we only need to detect EV_WRITE for a connect event.
	assert(flags == EV_WRITE);

	// remove the connect event
	assert(ct->connect_event);
	event_free(ct->connect_event);
	ct->connect_event = NULL;

	// we are no longer connected.  We are either connected, or not.
	assert(BIT_TEST(ct->flags, FLAG_CONTROLLER_CONNECTING));
	BIT_CLEAR(ct->flags, FLAG_CONTROLLER_CONNECTING);

	// check to see if we really are connected.
	foo = sizeof(error);
	getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &foo);
	if (error == ECONNREFUSED) {
		// we were connecting, but couldn't.
		BIT_SET(ct->flags, FLAG_CONTROLLER_CLOSED);

		// close the socket that didn't connect.
		close(fd);

		//set the action so that we can attempt to reconnect.
		assert(ct->connect_event == NULL);
		assert(sysdata->evbase);
		ct->connect_event = evtimer_new(sysdata->evbase, controller_wait_handler, (void *) ct);
		evtimer_add(ct->connect_event, &t);
	}
	else {
		logger(((system_data_t *)ct->sysdata)->logging, 2,
			"connected to remote controller: %s", ct->target);
	
		// create the node object.
		node = node_create(sysdata, fd);
	
		// add node to the main nodes list.
		ct->node = node;
		assert(node->controller == NULL);
		node->controller = ct;
		BIT_SET(node->flags, FLAG_NODE_CONTROLLER);
	
		// we need to check to see if we have any queues with active consumers,
		// and if we do, then we need to send consume requests to this node for
		// each one.
		assert(sysdata->queues);
		ll_start(sysdata->queues);
		while ((q = ll_next(sysdata->queues))) {
			assert(q->qid > 0);
			assert(q->name);
	
			if (ll_count(&q->nodes_busy) > 0 || ll_count(&q->nodes_ready) > 0) {
				logger(((system_data_t *)ct->sysdata)->logging, 2, 
					"Sending queue consume ('%s') to alternate controller at %s",
					q->name, ct->target );

				exclusive = 0;
				if (BIT_TEST(q->flags, QUEUE_FLAG_EXCLUSIVE))
					exclusive = 1;
				
				sendConsume(node, q->name, 1, RQ_PRIORITY_LOW, exclusive);
				ll_push_head(&q->nodes_consuming, node);
			}
		}
		ll_finish(sysdata->queues);
	}
}





void controller_connect(controller_t *ct)
{
	evutil_socket_t sock;
	int result;
	int len;

	assert(ct);
	assert(ct->target);
	assert(ct->node == NULL);
	assert(BIT_TEST(ct->flags, FLAG_CONTROLLER_CONNECTED) == 0);
	assert(BIT_TEST(ct->flags, FLAG_CONTROLLER_FAILED) == 0);
	assert(BIT_TEST(ct->flags, FLAG_CONTROLLER_CONNECTING) == 0);

	// if not already resolved.... resolve the target.
	if (BIT_TEST(ct->flags, FLAG_CONTROLLER_RESOLVED) == 0) {
		assert(ct->flags == 0);
		
		logger(((system_data_t *)ct->sysdata)->logging, 3, "resolving controller %s.", ct->target);

		len = sizeof(ct->saddr);
		if (evutil_parse_sockaddr_port(ct->target, &ct->saddr, &len) == 0) {
			BIT_SET(ct->flags, FLAG_CONTROLLER_RESOLVED);
		}
		else {
			BIT_SET(ct->flags, FLAG_CONTROLLER_FAILED);
		}
	}
	

	if (BIT_TEST(ct->flags, FLAG_CONTROLLER_FAILED) == 0) {
		assert(BIT_TEST(ct->flags, FLAG_CONTROLLER_RESOLVED));

		BIT_SET(ct->flags, FLAG_CONTROLLER_CONNECTING);

		sock = socket(AF_INET,SOCK_STREAM,0);
		assert(sock >= 0);
						
		// Before we attempt to connect, set the socket to non-blocking mode.
		evutil_make_socket_nonblocking(sock);

		logger(((system_data_t *)ct->sysdata)->logging, 3, "Attempting Remote connect to %s.", ct->target);

		result = connect(sock, &ct->saddr, sizeof(struct sockaddr));
		assert(result < 0);
		assert(errno == EINPROGRESS);

		// connect process has been started.  Now we need to create an event so that we know when the connect has completed.
		assert(ct->connect_event == NULL);
		assert(ct->sysdata);
		assert(((system_data_t *)ct->sysdata)->evbase);
		ct->connect_event = event_new(((system_data_t *)ct->sysdata)->evbase, sock, EV_WRITE, controller_connect_handler, ct);
		event_add(ct->connect_event, NULL);
	}
	else {
		assert(ct->target);
		logger(((system_data_t *)ct->sysdata)->logging, 2, "Remote connect to %s has failed.", ct->target);
	}
}
Example #13
0
File: stats.c Project: hyper/rqd
static void stats_handler(int fd, short int flags, void *arg)
{
	stats_t *stats;
	system_data_t *sysdata;
	int clients;
	int queues;
	int msg_pending, msg_proc;
	queue_t *q;

	assert(fd < 0);
	assert((flags & EV_TIMEOUT) == EV_TIMEOUT);
	assert(arg);

	stats = arg;

	// clear the stats event.
	assert(stats->stats_event);
	event_free(stats->stats_event);
	stats->stats_event = NULL;
	
	assert(stats->sysdata);
	sysdata = stats->sysdata;
	
// 	assert(stats->sysdata->server != NULL);
// 	server = stats->sysdata->server;

	assert(sysdata->nodelist);
	clients = ll_count(sysdata->nodelist);

	queues = 0;
	msg_pending = 0;
	msg_proc = 0;
	ll_start(sysdata->queues);
	while ((q = ll_next(sysdata->queues))) {
		queues ++;
		msg_pending += ll_count(&q->msg_pending);
		msg_proc += ll_count(&q->msg_proc);
	}
	ll_finish(sysdata->queues);

	assert(stats != NULL);
	if (stats->in_bytes || stats->out_bytes || stats->requests || stats->replies || stats->broadcasts || stats->re || stats->we) {

		logger(sysdata->logging, 1, "Bytes[%u/%u], Clients[%u], Requests[%u], Replies[%u], Broadcasts[%u], Queues[%u], Msgs[%d/%d], MsgPool[%u/%u], Events[%u/%u/%u]",
			stats->in_bytes,
			stats->out_bytes,
			clients,
			stats->requests,
			stats->replies,
			stats->broadcasts,
			queues,
			msg_pending, msg_proc,
			sysdata->msg_used, sysdata->msg_max,
			stats->re, stats->we, stats->te);
		
		stats->in_bytes = 0;
		stats->out_bytes = 0;
		stats->requests = 0;
		stats->replies = 0;
		stats->broadcasts = 0;
		stats->re = 0;
		stats->we = 0;
		stats->te = 0;
	}

	// if we are not shutting down, then schedule the stats event again.
	if (stats->shutdown == 0) {
		stats_start(stats);
	}
}
Example #14
0
File: signals.c Project: hyper/rq
//-----------------------------------------------------------------------------
// When the SIGINT signal is received, we need to start shutting down the
// service.  This means that it needs to:
//   1.  Close the listening socket.
//   2.  Send a CLOSING message to every connected node.
//   3.  if there are any undelivered messages in the queues, we need to return them.
//   4.  Shutdown the nodes if we can.
//   5.  Shutdown the queues if we can.
//   6.  Tell the stats system to close its event as soon as there are no more nodes connected.
void sigint_handler(evutil_socket_t fd, short what, void *arg)
{
	system_data_t *sysdata = (system_data_t *) arg;
	server_t *server;
	stats_t *stats;
	queue_t *q;
	node_t *node;
	controller_t *ct;
	
	logger(sysdata->logging, 3, "SIGINT");

	assert(sysdata);
	assert(sysdata->servers);

	// delete the sigint event, we dont need it anymore.
	assert(sysdata->sigint_event);
	event_free(sysdata->sigint_event);
	sysdata->sigint_event = NULL;

	// delete the sighup event, we dont need that either.
	assert(sysdata->sighup_event);
	event_free(sysdata->sighup_event);
	sysdata->sighup_event = NULL;

	// delete the sigusr1 event, we dont need that either.
	assert(sysdata->sigusr1_event);
	event_free(sysdata->sigusr1_event);
	sysdata->sigusr1_event = NULL;

	// delete the sigusr2 event, we dont need that either.
	assert(sysdata->sigusr2_event);
	event_free(sysdata->sigusr2_event);
	sysdata->sigusr2_event = NULL;

	logger(sysdata->logging, 2, "Shutting down servers.");
	while ((server = ll_pop_head(sysdata->servers))) {
		server_shutdown(server);
		server_free(server);
		free(server);
	}

	// All active nodes should be informed that we are shutting down.
	logger(sysdata->logging, 2, "Shutting down nodes.");
	assert(sysdata->nodelist);
	ll_start(sysdata->nodelist);
	while ((node = ll_next(sysdata->nodelist))) {
		assert(node->handle > 0);
		logger(sysdata->logging, 2, "Initiating shutdown of node %d.", node->handle);
		node_shutdown(node);
	}
	ll_finish(sysdata->nodelist);

	// Now attempt to shutdown all the queues.  Basically, this just means that the queue will close down all the 'waiting' consumers.
	logger(sysdata->logging, 2, "Initiating shutdown of queues.");
	ll_start(sysdata->queues);
	while ((q = ll_next(sysdata->queues))) {
		assert(q->name != NULL);
		assert(q->qid > 0);
		logger(sysdata->logging, 2, "Initiating shutdown of queue %d ('%s').", q->qid, q->name);
		queue_shutdown(q);
	}
	ll_finish(sysdata->queues);

	// if we have controllers that are attempting to connect, we need to change their status so that they dont.
	logger(sysdata->logging, 2, "Stopping controllers that are connecting.");
	ll_start(sysdata->controllers);
	while ((ct = ll_next(sysdata->controllers))) {
		BIT_SET(ct->flags, FLAG_CONTROLLER_FAILED);
		if (ct->connect_event) {
			event_free(ct->connect_event);
			ct->connect_event = NULL;
		}
	}
	ll_finish(sysdata->controllers);

	// Put stats event on notice that we are shutting down, so that as soon as there are no more nodes, it needs to stop its event.
	assert(sysdata != NULL);
	assert(sysdata->stats != NULL);
	stats = sysdata->stats;
	assert(stats->shutdown == 0);
	stats->shutdown ++;

	// Tell the logging system not to use events anymore.
	log_direct(sysdata->logging);
}