i_comm_manager.c 4.15 KB
/**
 * \file
 *
 * \author	Georg Hopp
 *
 * \copyright
 * Copyright © 2014 Georg Hopp
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <poll.h>

#include "trbase.h"
#include "trevent.h"

#include "tr/interface/comm_manager.h"
#include "tr/comm_end_point.h"
#include "tr/comm_manager.h"

TR_CREATE_INTERFACE(TR_CommManager, 8);

void
TR_commManagerAddEndpoint(void * _this, TR_CommEndPoint endpoint)
{
	TR_CommManager this = _this;

	if (this->endpoints[endpoint->transport->handle]) {
		// this should never happen, but if so we assume this is a leftover
		// that still has to be deleted.
		TR_delete(this->endpoints[endpoint->transport->handle]);
	}

	this->max_handle = endpoint->transport->handle > this->max_handle
		? endpoint->transport->handle
		: this->max_handle;

	this->endpoints[endpoint->transport->handle] = endpoint;
	TR_CALL(_this, TR_CommManager, addEndpoint, endpoint);
}

TR_EventDone
TR_commManagerSelect(void * _this, TR_Event event)
{
	int                  timeout;  // milliseconds
	int                * timeoutptr = event->data;
	TR_EventDispatcher   dispatcher = (TR_EventDispatcher)event->subject;

	if (NULL == timeoutptr) {
		timeout = TR_eventDispatcherGetDataWaitTime(dispatcher);
	} else {
		timeout = *timeoutptr;
	}

	TR_CALL(_this, TR_CommManager, select, event, timeout);

	return TR_EVENT_DONE;
}

TR_EventDone
TR_commManagerEnableWrite(void * _this, TR_Event event)
{
	TR_CALL(_this, TR_CommManager, enableWrite, event);

	return TR_EVENT_DONE;
}

TR_EventDone
TR_commManagerDisableWrite(void * _this, TR_Event event)
{
	TR_EventHandler this     = _this;
	TR_CommEndPoint endpoint = (TR_CommEndPoint)event->subject;

	TR_CALL(_this, TR_CommManager, disableWrite, event);

	if (TR_socketFinRd(endpoint->transport)) {
		TR_eventHandlerIssueEvent(
				this,
				TR_eventSubjectEmit(
					event->subject,
					TR_CEP_EVENT_SHUT_READ,
					NULL));
	}

	return TR_EVENT_DONE;
}

TR_EventDone
TR_commManagerEnableRead(void * _this, TR_Event event)
{
	TR_CALL(_this, TR_CommManager, enableRead, event);

	return TR_EVENT_DONE;
}

TR_EventDone
TR_commManagerClose(void * _this, TR_Event event)
{
	TR_CommManager  this     = _this;
	TR_CommEndPoint endpoint = (TR_CommEndPoint)event->subject;

	TR_socketShutdown(endpoint->transport);
	TR_CALL(_this, TR_CommManager, close, event);

	if (endpoint->transport->handle == this->max_handle) {
		while (! this->endpoints[--this->max_handle]);
	}
	TR_delete(this->endpoints[endpoint->transport->handle]);

	return TR_EVENT_DONE;
}

TR_EventDone
TR_commManagerShutdownRead(void * _this, TR_Event event)
{
	TR_CALL(_this, TR_CommManager, shutdownRead, event);

	if (TR_socketFinRdWr(((TR_CommEndPoint)event->subject)->transport)) {
		// close
		TR_eventHandlerIssueEvent(
				(TR_EventHandler)_this,
				TR_eventSubjectEmit(
					event->subject,
					TR_CEP_EVENT_CLOSE,
					NULL));
	} else if (! TR_cepHasPendingData((TR_CommEndPoint)event->subject)) {
		// handle pending data... close is issued from disableWrite
		TR_eventHandlerIssueEvent(
				(TR_EventHandler)_this,
				TR_eventSubjectEmit(
					event->subject,
					TR_CEP_EVENT_CLOSE,
					NULL));
	} else {
		TR_cepSetClose((TR_CommEndPoint)event->subject);
	}

	return TR_EVENT_DONE;
}

TR_EventDone
TR_commManagerShutdownWrite(void * _this, TR_Event event)
{
	TR_CALL(_this, TR_CommManager, shutdownWrite, event);

	if (TR_socketFinRd(((TR_CommEndPoint)event->subject)->transport)) {
		TR_eventHandlerIssueEvent(
				(TR_EventHandler)_this,
				TR_eventSubjectEmit(
					event->subject,
					TR_CEP_EVENT_CLOSE,
					NULL));
	}

	return TR_EVENT_DONE;
}

// vim: set ts=4 sw=4: