tunala.c 35.3 KB
Newer Older
	if(item->dirty_read != -1)
		close(item->dirty_read);
	if(item->dirty_send != item->dirty_read)
		close(item->dirty_send);
	item->dirty_read = item->dirty_send = -1;
	state_machine_close(&item->sm);
	/* OK, now we fix the item array */
	if(idx + 1 < world->tunnels_used)
		/* We need to scroll entries to the left */
		memmove(world->tunnels + idx,
				world->tunnels + (idx + 1),
				(world->tunnels_used - (idx + 1)) *
					sizeof(tunala_item_t));
	world->tunnels_used--;
}

static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item)
{
	int c_r, c_s, d_r, d_s; /* Four boolean flags */

	/* Take ourselves out of the gene-pool if there was an except */
	if((item->clean_read != -1) && FD_ISSET(item->clean_read,
				&selector->last_selected.excepts))
		return 0;
	if((item->clean_send != -1) && FD_ISSET(item->clean_send,
				&selector->last_selected.excepts))
		return 0;
	if((item->dirty_read != -1) && FD_ISSET(item->dirty_read,
				&selector->last_selected.excepts))
		return 0;
	if((item->dirty_send != -1) && FD_ISSET(item->dirty_send,
				&selector->last_selected.excepts))
		return 0;
	/* Grab our 4 IO flags */
	c_r = c_s = d_r = d_s = 0;
	if(item->clean_read != -1)
		c_r = FD_ISSET(item->clean_read, &selector->last_selected.reads);
	if(item->clean_send != -1)
		c_s = FD_ISSET(item->clean_send, &selector->last_selected.sends);
	if(item->dirty_read != -1)
		d_r = FD_ISSET(item->dirty_read, &selector->last_selected.reads);
	if(item->dirty_send != -1)
		d_s = FD_ISSET(item->dirty_send, &selector->last_selected.sends);
	/* If no IO has happened for us, skip needless data looping */
	if(!c_r && !c_s && !d_r && !d_s)
		return 1;
	if(c_r)
		c_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
				SM_CLEAN_IN), item->clean_read) <= 0);
	if(c_s)
		c_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
				SM_CLEAN_OUT), item->clean_send) <= 0);
	if(d_r)
		d_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
				SM_DIRTY_IN), item->dirty_read) <= 0);
	if(d_s)
		d_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
				SM_DIRTY_OUT), item->dirty_send) <= 0);
	/* If any of the flags is non-zero, that means they need closing */
	if(c_r) {
		close(item->clean_read);
		if(item->clean_send == item->clean_read)
			item->clean_send = -1;
		item->clean_read = -1;
	}
	if(c_s && (item->clean_send != -1)) {
		close(item->clean_send);
		if(item->clean_send == item->clean_read)
			item->clean_read = -1;
		item->clean_send = -1;
	}
	if(d_r) {
		close(item->dirty_read);
		if(item->dirty_send == item->dirty_read)
			item->dirty_send = -1;
		item->dirty_read = -1;
	}
	if(d_s && (item->dirty_send != -1)) {
		close(item->dirty_send);
		if(item->dirty_send == item->dirty_read)
			item->dirty_read = -1;
		item->dirty_send = -1;
	}
	/* This function name is attributed to the term donated by David
	 * Schwartz on openssl-dev, message-ID:
	 * <NCBBLIEPOCNJOAEKBEAKEEDGLIAA.davids@webmaster.com>. :-) */
	if(!state_machine_churn(&item->sm))
		/* If the SSL closes, it will also zero-out the _in buffers
		 * and will in future process just outgoing data. As and
		 * when the outgoing data has gone, it will return zero
		 * here to tell us to bail out. */
		return 0;
	/* Otherwise, we return zero if both sides are dead. */
	if(((item->clean_read == -1) || (item->clean_send == -1)) &&
			((item->dirty_read == -1) || (item->dirty_send == -1)))
		return 0;
	/* If only one side closed, notify the SSL of this so it can take
	 * appropriate action. */
	if((item->clean_read == -1) || (item->clean_send == -1)) {
		if(!state_machine_close_clean(&item->sm))
			return 0;
	}
	if((item->dirty_read == -1) || (item->dirty_send == -1)) {
		if(!state_machine_close_dirty(&item->sm))
			return 0;
	}
	return 1;
}