* Implemented select support for sockets and notifications, not yet tested, though;
this closes ticket #811. * Added notification support to IPv4 and UDP. * Implemented reading out SO_ERROR. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19017 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -9,6 +9,9 @@
|
||||
#include <net_buffer.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <Select.h>
|
||||
#include <lock.h>
|
||||
|
||||
|
||||
#define NET_SOCKET_MODULE_NAME "network/stack/socket/v1"
|
||||
|
||||
@@ -31,6 +34,11 @@ typedef struct net_socket {
|
||||
uint32 low_water_mark;
|
||||
bigtime_t timeout;
|
||||
} send, receive;
|
||||
|
||||
// TODO: could be moved into a private structure
|
||||
status_t error;
|
||||
struct select_sync_pool *select_pool;
|
||||
benaphore lock;
|
||||
} net_socket;
|
||||
|
||||
struct net_socket_module_info {
|
||||
@@ -53,6 +61,13 @@ struct net_socket_module_info {
|
||||
status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
|
||||
net_buffer **_buffer);
|
||||
|
||||
// notifications
|
||||
status_t (*request_notification)(net_socket *socket, uint8 event, uint32 ref,
|
||||
selectsync *sync);
|
||||
status_t (*cancel_notification)(net_socket *socket, uint8 event,
|
||||
selectsync *sync);
|
||||
status_t (*notify)(net_socket *socket, uint8 event, int32 value);
|
||||
|
||||
// standard socket API
|
||||
int (*accept)(net_socket *socket, struct sockaddr *address,
|
||||
socklen_t *_addressLength, net_socket **_acceptedSocket);
|
||||
|
||||
@@ -76,6 +76,9 @@ struct net_stack_module_info {
|
||||
|
||||
// Utility Functions
|
||||
|
||||
// notification
|
||||
status_t (*notify_socket)(struct net_socket *socket, uint8 event, int32 value);
|
||||
|
||||
// checksum
|
||||
uint16 (*checksum)(uint8 *buffer, size_t length);
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ typedef DoublyLinkedList<class RawSocket> RawSocketList;
|
||||
|
||||
class RawSocket : public DoublyLinkedListLinkImpl<RawSocket> {
|
||||
public:
|
||||
RawSocket();
|
||||
RawSocket(net_socket *socket);
|
||||
~RawSocket();
|
||||
|
||||
status_t InitCheck();
|
||||
@@ -127,6 +127,7 @@ class RawSocket : public DoublyLinkedListLinkImpl<RawSocket> {
|
||||
status_t Write(net_buffer *buffer);
|
||||
|
||||
private:
|
||||
net_socket *fSocket;
|
||||
net_fifo fFifo;
|
||||
};
|
||||
|
||||
@@ -153,7 +154,9 @@ static benaphore sFragmentLock;
|
||||
static hash_table *sFragmentHash;
|
||||
|
||||
|
||||
RawSocket::RawSocket()
|
||||
RawSocket::RawSocket(net_socket *socket)
|
||||
:
|
||||
fSocket(socket)
|
||||
{
|
||||
status_t status = sStackModule->init_fifo(&fFifo, "ipv4 raw socket", 65536);
|
||||
if (status < B_OK)
|
||||
@@ -211,7 +214,13 @@ RawSocket::Write(net_buffer *source)
|
||||
if (buffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return sStackModule->fifo_enqueue_buffer(&fFifo, buffer);
|
||||
status_t status = sStackModule->fifo_enqueue_buffer(&fFifo, buffer);
|
||||
if (status >= B_OK)
|
||||
sStackModule->notify_socket(fSocket, B_SELECT_READ, BytesAvailable());
|
||||
else
|
||||
sBufferModule->free(buffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -597,7 +606,7 @@ ipv4_open(net_protocol *_protocol)
|
||||
{
|
||||
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||
|
||||
RawSocket *raw = new (std::nothrow) RawSocket;
|
||||
RawSocket *raw = new (std::nothrow) RawSocket(protocol->socket);
|
||||
if (raw == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
|
||||
@@ -871,7 +871,9 @@ UdpEndpoint::StoreData(net_buffer *_buffer)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t status = sStackModule->fifo_enqueue_buffer(&fFifo, buffer);
|
||||
if (status < B_OK)
|
||||
if (status >= B_OK)
|
||||
sStackModule->notify_socket(socket, B_SELECT_READ, BytesAvailable());
|
||||
else
|
||||
sBufferModule->free(buffer);
|
||||
|
||||
return status;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <util/list.h>
|
||||
#include <fs/select_sync_pool.h>
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
@@ -32,6 +33,10 @@ create_socket(int family, int type, int protocol, net_socket **_socket)
|
||||
socket->type = type;
|
||||
socket->protocol = protocol;
|
||||
|
||||
status_t status = benaphore_init(&socket->lock, "socket");
|
||||
if (status < B_OK)
|
||||
goto err1;
|
||||
|
||||
// set defaults (may be overridden by the protocols)
|
||||
socket->send.buffer_size = 65536;
|
||||
socket->send.low_water_mark = 1;
|
||||
@@ -40,21 +45,26 @@ create_socket(int family, int type, int protocol, net_socket **_socket)
|
||||
socket->receive.low_water_mark = 1;
|
||||
socket->receive.timeout = B_INFINITE_TIMEOUT;
|
||||
|
||||
status_t status = get_domain_protocols(socket);
|
||||
if (status < B_OK) {
|
||||
delete socket;
|
||||
return status;
|
||||
}
|
||||
socket->select_pool = NULL;
|
||||
|
||||
status = get_domain_protocols(socket);
|
||||
if (status < B_OK)
|
||||
goto err2;
|
||||
|
||||
status = socket->first_info->open(socket->first_protocol);
|
||||
if (status < B_OK) {
|
||||
put_domain_protocols(socket);
|
||||
delete socket;
|
||||
return status;
|
||||
}
|
||||
if (status < B_OK)
|
||||
goto err3;
|
||||
|
||||
*_socket = socket;
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
put_domain_protocols(socket);
|
||||
err2:
|
||||
benaphore_destroy(&socket->lock);
|
||||
err1:
|
||||
delete socket;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +81,8 @@ socket_free(net_socket *socket)
|
||||
status_t status = socket->first_info->free(socket->first_protocol);
|
||||
|
||||
put_domain_protocols(socket);
|
||||
benaphore_destroy(&socket->lock);
|
||||
delete_select_sync_pool(socket->select_pool);
|
||||
delete socket;
|
||||
|
||||
return status;
|
||||
@@ -166,6 +178,96 @@ socket_receive_data(net_socket *socket, size_t length, uint32 flags,
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - notifications
|
||||
|
||||
|
||||
status_t
|
||||
socket_request_notification(net_socket *socket, uint8 event, uint32 ref,
|
||||
selectsync *sync)
|
||||
{
|
||||
benaphore_lock(&socket->lock);
|
||||
|
||||
status_t status = add_select_sync_pool_entry(&socket->select_pool, sync,
|
||||
ref, event);
|
||||
if (status < B_OK) {
|
||||
benaphore_unlock(&socket->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
// check if the event is already present
|
||||
// TODO: add support for poll() types
|
||||
|
||||
switch (event) {
|
||||
case B_SELECT_READ:
|
||||
{
|
||||
ssize_t available = socket_read_avail(socket);
|
||||
if ((ssize_t)socket->receive.low_water_mark <= available || available < B_OK)
|
||||
notify_select_event(sync, ref, event);
|
||||
break;
|
||||
}
|
||||
case B_SELECT_WRITE:
|
||||
{
|
||||
ssize_t available = socket_send_avail(socket);
|
||||
if ((ssize_t)socket->send.low_water_mark <= available || available < B_OK)
|
||||
notify_select_event(sync, ref, event);
|
||||
break;
|
||||
}
|
||||
case B_SELECT_ERROR:
|
||||
// TODO: B_SELECT_ERROR condition!
|
||||
break;
|
||||
}
|
||||
|
||||
benaphore_unlock(&socket->lock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
socket_cancel_notification(net_socket *socket, uint8 event, selectsync *sync)
|
||||
{
|
||||
benaphore_lock(&socket->lock);
|
||||
|
||||
status_t status = remove_select_sync_pool_entry(&socket->select_pool,
|
||||
sync, event);
|
||||
|
||||
benaphore_unlock(&socket->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
socket_notify(net_socket *socket, uint8 event, int32 value)
|
||||
{
|
||||
benaphore_lock(&socket->lock);
|
||||
|
||||
bool notify = true;
|
||||
|
||||
switch (event) {
|
||||
case B_SELECT_READ:
|
||||
{
|
||||
if ((ssize_t)socket->receive.low_water_mark > value && value >= B_OK)
|
||||
notify = false;
|
||||
break;
|
||||
}
|
||||
case B_SELECT_WRITE:
|
||||
{
|
||||
if ((ssize_t)socket->send.low_water_mark > value && value >= B_OK)
|
||||
notify = false;
|
||||
break;
|
||||
}
|
||||
case B_SELECT_ERROR:
|
||||
socket->error = value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (notify && socket->select_pool)
|
||||
notify_select_event_pool(socket->select_pool, event);
|
||||
|
||||
benaphore_unlock(&socket->lock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - standard socket API
|
||||
|
||||
|
||||
@@ -306,6 +408,17 @@ socket_getsockopt(net_socket *socket, int level, int option, void *value,
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
case SO_ERROR:
|
||||
{
|
||||
int32 *_set = (int32 *)value;
|
||||
*_set = socket->error;
|
||||
*_length = sizeof(int32);
|
||||
|
||||
socket->error = B_OK;
|
||||
// clear error upon retrieval
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -572,6 +685,11 @@ net_socket_module_info gNetSocketModule = {
|
||||
socket_send_data,
|
||||
socket_receive_data,
|
||||
|
||||
// notifications
|
||||
socket_request_notification,
|
||||
socket_cancel_notification,
|
||||
socket_notify,
|
||||
|
||||
// standard socket API
|
||||
socket_accept,
|
||||
socket_bind,
|
||||
|
||||
@@ -910,6 +910,8 @@ static net_stack_module_info sNetStackModule = {
|
||||
unregister_device_monitor,
|
||||
device_removed,
|
||||
|
||||
notify_socket,
|
||||
|
||||
checksum,
|
||||
|
||||
init_fifo,
|
||||
|
||||
@@ -63,6 +63,16 @@ checksum(uint8 *buffer, size_t length)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Notifications
|
||||
|
||||
|
||||
status_t
|
||||
notify_socket(net_socket *socket, uint8 event, int32 value)
|
||||
{
|
||||
return gNetSocketModule.notify(socket, event, value);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - FIFOs
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
uint16 compute_checksum(uint8 *_buffer, size_t length);
|
||||
uint16 checksum(uint8 *buffer, size_t length);
|
||||
|
||||
// notifications
|
||||
status_t notify_socket(net_socket *socket, uint8 event, int32 value);
|
||||
|
||||
// fifos
|
||||
status_t init_fifo(net_fifo *fifo, const char *name, size_t maxBytes);
|
||||
void uninit_fifo(net_fifo *fifo);
|
||||
|
||||
Reference in New Issue
Block a user