diff options
Diffstat (limited to 'src/libcharon/network/socket_manager.c')
| -rw-r--r-- | src/libcharon/network/socket_manager.c | 63 | 
1 files changed, 50 insertions, 13 deletions
diff --git a/src/libcharon/network/socket_manager.c b/src/libcharon/network/socket_manager.c index 0dbce4b1b..72a454301 100644 --- a/src/libcharon/network/socket_manager.c +++ b/src/libcharon/network/socket_manager.c @@ -1,4 +1,6 @@  /* + * Copyright (C) 2010 Tobias Brunner + * Hochschule fuer Technik Rapperswil   * Copyright (C) 2010 Martin Willi   * Copyright (C) 2010 revosec AG   * @@ -33,11 +35,21 @@ struct private_socket_manager_t {  	socket_manager_t public;  	/** -	 * List of registered socket +	 * List of registered socket constructors  	 */  	linked_list_t *sockets;  	/** +	 * Instantiated socket implementation +	 */ +	socket_t *socket; + +	/** +	 * The constructor used to create the current socket +	 */ +	socket_constructor_t create; + +	/**  	 * Lock for sockets list  	 */  	rwlock_t *lock; @@ -46,11 +58,9 @@ struct private_socket_manager_t {  METHOD(socket_manager_t, receiver, status_t,  	private_socket_manager_t *this, packet_t **packet)  { -	socket_t *socket;  	status_t status; -  	this->lock->read_lock(this->lock); -	if (this->sockets->get_first(this->sockets, (void**)&socket) != SUCCESS) +	if (!this->socket)  	{  		DBG1(DBG_NET, "no socket implementation registered, receiving failed");  		this->lock->unlock(this->lock); @@ -58,7 +68,7 @@ METHOD(socket_manager_t, receiver, status_t,  	}  	/* receive is blocking and the thread can be cancelled */  	thread_cleanup_push((thread_cleanup_t)this->lock->unlock, this->lock); -	status = socket->receive(socket, packet); +	status = this->socket->receive(this->socket, packet);  	thread_cleanup_pop(TRUE);  	return status;  } @@ -66,40 +76,67 @@ METHOD(socket_manager_t, receiver, status_t,  METHOD(socket_manager_t, sender, status_t,  	private_socket_manager_t *this, packet_t *packet)  { -	socket_t *socket;  	status_t status; -  	this->lock->read_lock(this->lock); -	if (this->sockets->get_first(this->sockets, (void**)&socket) != SUCCESS) +	if (!this->socket)  	{  		DBG1(DBG_NET, "no socket implementation registered, sending failed");  		this->lock->unlock(this->lock);  		return NOT_SUPPORTED;  	} -	status = socket->send(socket, packet); +	status = this->socket->send(this->socket, packet);  	this->lock->unlock(this->lock);  	return status;  } +static void create_socket(private_socket_manager_t *this) +{ +	socket_constructor_t create; +	/* remove constructors in order to avoid trying to create broken ones +	 * multiple times */ +	while (this->sockets->remove_first(this->sockets, +									   (void**)&create) == SUCCESS) +	{ +		this->socket = create(); +		if (this->socket) +		{ +			this->create = create; +			break; +		} +	} +} +  METHOD(socket_manager_t, add_socket, void, -	private_socket_manager_t *this, socket_t *socket) +	private_socket_manager_t *this, socket_constructor_t create)  {  	this->lock->write_lock(this->lock); -	this->sockets->insert_last(this->sockets, socket); +	this->sockets->insert_last(this->sockets, create); +	if (!this->socket) +	{ +		create_socket(this); +	}  	this->lock->unlock(this->lock);  }  METHOD(socket_manager_t, remove_socket, void, -	private_socket_manager_t *this, socket_t *socket) +	private_socket_manager_t *this, socket_constructor_t create)  {  	this->lock->write_lock(this->lock); -	this->sockets->remove(this->sockets, socket, NULL); +	this->sockets->remove(this->sockets, create, NULL); +	if (this->create == create) +	{ +		this->socket->destroy(this->socket); +		this->socket = NULL; +		this->create = NULL; +		create_socket(this); +	}  	this->lock->unlock(this->lock);  }  METHOD(socket_manager_t, destroy, void,  	private_socket_manager_t *this)  { +	DESTROY_IF(this->socket);  	this->sockets->destroy(this->sockets);  	this->lock->destroy(this->lock);  	free(this);  | 
