Implemented backlog/pending connection support to the sockets - while currently

only TCP needs this, other stream oriented protocols might too, in the future.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19236 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-11-09 18:53:18 +00:00
parent b12912bead
commit 1a0e92a33b
2 changed files with 138 additions and 8 deletions

View File

@ -36,6 +36,13 @@ typedef struct net_socket {
} send, receive;
// TODO: could be moved into a private structure
struct net_socket *parent;
struct list_link link;
uint32 max_backlog;
uint32 child_count;
struct list pending_children;
struct list connected_children;
status_t error;
struct select_sync_pool *select_pool;
benaphore lock;
@ -61,6 +68,13 @@ struct net_socket_module_info {
status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
net_buffer **_buffer);
// connections
status_t (*spawn_pending_socket)(net_socket *parent, net_socket **_socket);
void (*delete_socket)(net_socket *socket);
status_t (*dequeue_connected)(net_socket *parent, net_socket **_socket);
status_t (*set_max_backlog)(net_socket *socket, uint32 backlog);
status_t (*set_connected)(net_socket *socket);
// notifications
status_t (*request_notification)(net_socket *socket, uint8 event, uint32 ref,
selectsync *sync);

View File

@ -21,8 +21,11 @@
#include <string.h>
void socket_delete(net_socket *socket);
status_t
create_socket(int family, int type, int protocol, net_socket **_socket)
socket_create(int family, int type, int protocol, net_socket **_socket)
{
struct net_socket *socket = new (std::nothrow) net_socket;
if (socket == NULL)
@ -84,13 +87,11 @@ status_t
socket_free(net_socket *socket)
{
status_t status = socket->first_info->free(socket->first_protocol);
if (status == B_BUSY)
return B_OK;
put_domain_protocols(socket);
benaphore_destroy(&socket->lock);
delete_select_sync_pool(socket->select_pool);
delete socket;
return status;
socket_delete(socket);
return B_OK;
}
@ -183,6 +184,114 @@ socket_receive_data(net_socket *socket, size_t length, uint32 flags,
}
// #pragma mark - connections
status_t
socket_spawn_pending(net_socket *parent, net_socket **_socket)
{
net_socket *socket;
status_t status = socket_create(parent->family, parent->type, parent->protocol, &socket);
if (status < B_OK)
return status;
// inherit parent's properties
socket->send = parent->send;
socket->receive = parent->receive;
socket->options = parent->options;
socket->linger = parent->linger;
memcpy(&socket->address, &parent->address, parent->address.ss_len);
memcpy(&socket->peer, &parent->peer, parent->peer.ss_len);
// add to the parent's list of pending connections
list_add_item(&parent->pending_children, socket);
parent->child_count++;
*_socket = socket;
return B_OK;
}
void
socket_delete(net_socket *socket)
{
if (socket->parent != NULL)
panic("socket still has a parent!");
put_domain_protocols(socket);
benaphore_destroy(&socket->lock);
delete_select_sync_pool(socket->select_pool);
delete socket;
}
status_t
socket_dequeue_connected(net_socket *parent, net_socket **_socket)
{
benaphore_lock(&parent->lock);
net_socket *socket = (net_socket *)list_remove_head_item(&parent->connected_children);
if (socket != NULL) {
socket->parent = NULL;
parent->child_count--;
*_socket = socket;
}
benaphore_unlock(&parent->lock);
return socket != NULL ? B_OK : B_ENTRY_NOT_FOUND;
}
status_t
socket_set_max_backlog(net_socket *socket, uint32 backlog)
{
// we enforce an upper limit of connections waiting to be accepted
if (backlog > 256)
backlog = 256;
benaphore_lock(&socket->lock);
// first remove the pending connections, then the already connected ones as needed
net_socket *child;
while (socket->child_count > backlog
&& (child = (net_socket *)list_remove_tail_item(&socket->pending_children)) != NULL) {
child->parent = NULL;
socket->child_count--;
}
while (socket->child_count > backlog
&& (child = (net_socket *)list_remove_tail_item(&socket->connected_children)) != NULL) {
child->parent = NULL;
socket_delete(child);
socket->child_count--;
}
socket->max_backlog = backlog;
benaphore_unlock(&socket->lock);
return B_OK;
}
/*!
The socket has been connected. It will be moved to the connected queue
of its parent socket.
*/
status_t
socket_connected(net_socket *socket)
{
net_socket *parent = socket->parent;
if (parent == NULL)
return B_BAD_VALUE;
benaphore_lock(&parent->lock);
list_remove_item(&parent->pending_children, socket);
list_add_item(&parent->connected_children, socket);
benaphore_unlock(&parent->lock);
return B_OK;
}
// #pragma mark - notifications
@ -676,7 +785,7 @@ net_socket_module_info gNetSocketModule = {
0,
socket_std_ops
},
create_socket,
socket_create,
socket_close,
socket_free,
@ -690,6 +799,13 @@ net_socket_module_info gNetSocketModule = {
socket_send_data,
socket_receive_data,
// connections
socket_spawn_pending,
socket_delete,
socket_dequeue_connected,
socket_set_max_backlog,
socket_connected,
// notifications
socket_request_notification,
socket_cancel_notification,