* 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:
Axel Dörfler
2006-10-07 12:32:02 +00:00
parent fb4e373041
commit a7028ce680
8 changed files with 177 additions and 15 deletions
+15
View File
@@ -9,6 +9,9 @@
#include <net_buffer.h> #include <net_buffer.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <Select.h>
#include <lock.h>
#define NET_SOCKET_MODULE_NAME "network/stack/socket/v1" #define NET_SOCKET_MODULE_NAME "network/stack/socket/v1"
@@ -31,6 +34,11 @@ typedef struct net_socket {
uint32 low_water_mark; uint32 low_water_mark;
bigtime_t timeout; bigtime_t timeout;
} send, receive; } send, receive;
// TODO: could be moved into a private structure
status_t error;
struct select_sync_pool *select_pool;
benaphore lock;
} net_socket; } net_socket;
struct net_socket_module_info { 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, status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
net_buffer **_buffer); 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 // standard socket API
int (*accept)(net_socket *socket, struct sockaddr *address, int (*accept)(net_socket *socket, struct sockaddr *address,
socklen_t *_addressLength, net_socket **_acceptedSocket); socklen_t *_addressLength, net_socket **_acceptedSocket);
+3
View File
@@ -76,6 +76,9 @@ struct net_stack_module_info {
// Utility Functions // Utility Functions
// notification
status_t (*notify_socket)(struct net_socket *socket, uint8 event, int32 value);
// checksum // checksum
uint16 (*checksum)(uint8 *buffer, size_t length); uint16 (*checksum)(uint8 *buffer, size_t length);
@@ -115,7 +115,7 @@ typedef DoublyLinkedList<class RawSocket> RawSocketList;
class RawSocket : public DoublyLinkedListLinkImpl<RawSocket> { class RawSocket : public DoublyLinkedListLinkImpl<RawSocket> {
public: public:
RawSocket(); RawSocket(net_socket *socket);
~RawSocket(); ~RawSocket();
status_t InitCheck(); status_t InitCheck();
@@ -127,6 +127,7 @@ class RawSocket : public DoublyLinkedListLinkImpl<RawSocket> {
status_t Write(net_buffer *buffer); status_t Write(net_buffer *buffer);
private: private:
net_socket *fSocket;
net_fifo fFifo; net_fifo fFifo;
}; };
@@ -153,7 +154,9 @@ static benaphore sFragmentLock;
static hash_table *sFragmentHash; static hash_table *sFragmentHash;
RawSocket::RawSocket() RawSocket::RawSocket(net_socket *socket)
:
fSocket(socket)
{ {
status_t status = sStackModule->init_fifo(&fFifo, "ipv4 raw socket", 65536); status_t status = sStackModule->init_fifo(&fFifo, "ipv4 raw socket", 65536);
if (status < B_OK) if (status < B_OK)
@@ -211,7 +214,13 @@ RawSocket::Write(net_buffer *source)
if (buffer == NULL) if (buffer == NULL)
return B_NO_MEMORY; 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; ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
RawSocket *raw = new (std::nothrow) RawSocket; RawSocket *raw = new (std::nothrow) RawSocket(protocol->socket);
if (raw == NULL) if (raw == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -871,7 +871,9 @@ UdpEndpoint::StoreData(net_buffer *_buffer)
return B_NO_MEMORY; return B_NO_MEMORY;
status_t status = sStackModule->fifo_enqueue_buffer(&fFifo, buffer); 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); sBufferModule->free(buffer);
return status; return status;
+128 -10
View File
@@ -14,6 +14,7 @@
#include <KernelExport.h> #include <KernelExport.h>
#include <util/list.h> #include <util/list.h>
#include <fs/select_sync_pool.h>
#include <new> #include <new>
#include <stdlib.h> #include <stdlib.h>
@@ -32,6 +33,10 @@ create_socket(int family, int type, int protocol, net_socket **_socket)
socket->type = type; socket->type = type;
socket->protocol = protocol; 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) // set defaults (may be overridden by the protocols)
socket->send.buffer_size = 65536; socket->send.buffer_size = 65536;
socket->send.low_water_mark = 1; 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.low_water_mark = 1;
socket->receive.timeout = B_INFINITE_TIMEOUT; socket->receive.timeout = B_INFINITE_TIMEOUT;
status_t status = get_domain_protocols(socket); socket->select_pool = NULL;
if (status < B_OK) {
delete socket; status = get_domain_protocols(socket);
return status; if (status < B_OK)
} goto err2;
status = socket->first_info->open(socket->first_protocol); status = socket->first_info->open(socket->first_protocol);
if (status < B_OK) { if (status < B_OK)
put_domain_protocols(socket); goto err3;
delete socket;
return status;
}
*_socket = socket; *_socket = socket;
return B_OK; 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); status_t status = socket->first_info->free(socket->first_protocol);
put_domain_protocols(socket); put_domain_protocols(socket);
benaphore_destroy(&socket->lock);
delete_select_sync_pool(socket->select_pool);
delete socket; delete socket;
return status; 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 // #pragma mark - standard socket API
@@ -306,6 +408,17 @@ socket_getsockopt(net_socket *socket, int level, int option, void *value,
return B_OK; 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: default:
break; break;
} }
@@ -572,6 +685,11 @@ net_socket_module_info gNetSocketModule = {
socket_send_data, socket_send_data,
socket_receive_data, socket_receive_data,
// notifications
socket_request_notification,
socket_cancel_notification,
socket_notify,
// standard socket API // standard socket API
socket_accept, socket_accept,
socket_bind, socket_bind,
@@ -910,6 +910,8 @@ static net_stack_module_info sNetStackModule = {
unregister_device_monitor, unregister_device_monitor,
device_removed, device_removed,
notify_socket,
checksum, checksum,
init_fifo, 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 // #pragma mark - FIFOs
@@ -16,6 +16,9 @@
uint16 compute_checksum(uint8 *_buffer, size_t length); uint16 compute_checksum(uint8 *_buffer, size_t length);
uint16 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 // fifos
status_t init_fifo(net_fifo *fifo, const char *name, size_t maxBytes); status_t init_fifo(net_fifo *fifo, const char *name, size_t maxBytes);
void uninit_fifo(net_fifo *fifo); void uninit_fifo(net_fifo *fifo);