introduced a new helper class DatagramSocket which provides a consistent base interface and functionality for the implementation of datagram-based sockets.

- made the ipv4 raw, udp and link protocols use DatagramSocket.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20672 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos
2007-04-13 00:55:32 +00:00
parent effe53fae9
commit bfb45f717c
7 changed files with 355 additions and 173 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006, Haiku, Inc. All Rights Reserved. * Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef NET_BUFFER_UTILITIES_H #ifndef NET_BUFFER_UTILITIES_H
+288
View File
@@ -0,0 +1,288 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Hugo Santos, [email protected]
*/
#ifndef PROTOCOL_UTILITIES_H
#define PROTOCOL_UTILITIES_H
#include <lock.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
#include <net_buffer.h>
#include <net_socket.h>
#include <net_stack.h>
class BenaphoreLocking {
public:
typedef benaphore Type;
typedef BenaphoreLocker AutoLocker;
static status_t Init(benaphore *lock, const char *name)
{ return benaphore_init(lock, name); }
static void Destroy(benaphore *lock) { benaphore_destroy(lock); }
static status_t Lock(benaphore *lock) { return benaphore_lock(lock); }
static status_t Unlock(benaphore *lock) { return benaphore_unlock(lock); }
};
extern net_stack_module_info *gStackModule;
extern net_buffer_module_info *gBufferModule;
class NetModuleBundle {
public:
static net_stack_module_info *Stack() { return gStackModule; }
static net_buffer_module_info *Buffer() { return gBufferModule; }
};
template<typename LockingBase = BenaphoreLocking,
typename ModuleBundle = NetModuleBundle>
class DatagramSocket {
public:
DatagramSocket(const char *name, net_socket *socket);
~DatagramSocket();
status_t InitCheck() const;
status_t Enqueue(net_buffer *buffer);
status_t EnqueueClone(net_buffer *buffer);
net_buffer *Dequeue(bool clone);
status_t BlockingDequeue(bool clone, bigtime_t timeout,
net_buffer **_buffer);
status_t SocketDequeue(uint32 flags, net_buffer **_buffer);
void Clear();
size_t AvailableData() const;
void WakeAll();
protected:
status_t _Enqueue(net_buffer *buffer);
status_t _EnqueueClone(net_buffer *buffer);
net_buffer *_Dequeue(bool clone);
void _Clear();
status_t _Wait(bigtime_t timeout);
void _NotifyOneReader(bool notifySocket);
bool _IsEmpty() const { return fBuffers.IsEmpty(); }
bigtime_t _SocketTimeout(uint32 flags) const;
typedef typename LockingBase::Type LockType;
typedef typename LockingBase::AutoLocker AutoLocker;
typedef DoublyLinkedListCLink<net_buffer> NetBufferLink;
typedef DoublyLinkedList<net_buffer, NetBufferLink> BufferList;
status_t fStatus;
net_socket *fSocket;
sem_id fNotify;
BufferList fBuffers;
size_t fCurrentBytes;
mutable LockType fLock;
};
#define DECL_DATAGRAM_SOCKET(args) \
template<typename LockingBase, typename ModuleBundle> args \
DatagramSocket<LockingBase, ModuleBundle>
DECL_DATAGRAM_SOCKET(inline)::DatagramSocket(const char *name,
net_socket *socket)
: fSocket(socket), fCurrentBytes(0)
{
fStatus = LockingBase::Init(&fLock, name);
if (fStatus >= B_OK)
fNotify = create_sem(0, name);
}
DECL_DATAGRAM_SOCKET(inline)::~DatagramSocket()
{
_Clear();
if (fStatus >= B_OK) {
delete_sem(fNotify);
LockingBase::Destroy(&fLock);
}
}
DECL_DATAGRAM_SOCKET(inline status_t)::InitCheck() const
{
if (fStatus < 0)
return fStatus;
return fNotify;
}
DECL_DATAGRAM_SOCKET(inline status_t)::Enqueue(net_buffer *buffer)
{
AutoLocker _(fLock);
return _Enqueue(buffer);
}
DECL_DATAGRAM_SOCKET(inline status_t)::_Enqueue(net_buffer *buffer)
{
if (fSocket->receive.buffer_size > 0
&& (fCurrentBytes + buffer->size) > fSocket->receive.buffer_size)
return ENOBUFS;
fBuffers.Add(buffer);
fCurrentBytes += buffer->size;
_NotifyOneReader(true);
return B_OK;
}
DECL_DATAGRAM_SOCKET(inline status_t)::EnqueueClone(net_buffer *_buffer)
{
AutoLocker _(fLock);
return _EnqueueClone(_buffer);
}
DECL_DATAGRAM_SOCKET(inline status_t)::_EnqueueClone(net_buffer *_buffer)
{
net_buffer *buffer = ModuleBundle::Buffer()->clone(_buffer, false);
if (buffer == NULL)
return B_NO_MEMORY;
status_t status = _Enqueue(buffer);
if (status < B_OK)
ModuleBundle::Buffer()->free(buffer);
return status;
}
DECL_DATAGRAM_SOCKET(inline net_buffer *)::Dequeue(bool clone)
{
AutoLocker _(fLock);
return _Dequeue(clone);
}
DECL_DATAGRAM_SOCKET(inline net_buffer *)::_Dequeue(bool clone)
{
if (fBuffers.IsEmpty())
return NULL;
if (clone)
return ModuleBundle::Buffer()->clone(fBuffers.Head(), false);
net_buffer *buffer = fBuffers.RemoveHead();
fCurrentBytes -= buffer->size;
return buffer;
}
DECL_DATAGRAM_SOCKET(inline status_t)::BlockingDequeue(bool clone,
bigtime_t timeout, net_buffer **_buffer)
{
AutoLocker _(fLock);
bool waited = false;
while (fBuffers.IsEmpty()) {
status_t status = _Wait(timeout);
if (status < B_OK)
return status;
waited = true;
}
*_buffer = _Dequeue(clone);
if (clone && waited) {
// we were signalled there was a new buffer in the
// list; but since we are cloning, notify the next
// waiting reader.
_NotifyOneReader(false);
}
if (*_buffer == NULL)
return B_NO_MEMORY;
return B_OK;
}
DECL_DATAGRAM_SOCKET(inline status_t)::SocketDequeue(uint32 flags,
net_buffer **_buffer)
{
return BlockingDequeue(flags & MSG_PEEK, _SocketTimeout(flags), _buffer);
}
DECL_DATAGRAM_SOCKET(inline void)::Clear()
{
AutoLocker _(fLock);
_Clear();
}
DECL_DATAGRAM_SOCKET(inline void)::_Clear()
{
BufferList::Iterator it = fBuffers.GetIterator();
while (it.HasNext())
ModuleBundle::Buffer()->free(it.Next());
fCurrentBytes = 0;
}
DECL_DATAGRAM_SOCKET(inline size_t)::AvailableData() const
{
AutoLocker _(fLock);
return fCurrentBytes;
}
DECL_DATAGRAM_SOCKET(inline status_t)::_Wait(bigtime_t timeout)
{
LockingBase::Unlock(&fLock);
status_t status = acquire_sem_etc(fNotify, 1, B_CAN_INTERRUPT
| B_ABSOLUTE_TIMEOUT, timeout);
LockingBase::Lock(&fLock);
return status;
}
DECL_DATAGRAM_SOCKET(inline void)::WakeAll()
{
release_sem_etc(fNotify, 0, B_RELEASE_ALL);
}
DECL_DATAGRAM_SOCKET(inline void)::_NotifyOneReader(bool notifySocket)
{
release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY
| B_DO_NOT_RESCHEDULE);
if (notifySocket)
ModuleBundle::Stack()->notify_socket(fSocket, B_SELECT_READ,
fCurrentBytes);
}
DECL_DATAGRAM_SOCKET(inline bigtime_t)::_SocketTimeout(uint32 flags) const
{
bigtime_t timeout = fSocket->receive.timeout;
if (flags & MSG_DONTWAIT)
timeout = 0;
else if (timeout != 0 && timeout != B_INFINITE_TIMEOUT)
timeout += system_time();
return timeout;
}
#endif
@@ -13,6 +13,7 @@
#include <net_protocol.h> #include <net_protocol.h>
#include <net_stack.h> #include <net_stack.h>
#include <NetBufferUtilities.h> #include <NetBufferUtilities.h>
#include <ProtocolUtilities.h>
#include <ByteOrder.h> #include <ByteOrder.h>
#include <KernelExport.h> #include <KernelExport.h>
@@ -110,22 +111,9 @@ class FragmentPacket {
typedef DoublyLinkedList<class RawSocket> RawSocketList; typedef DoublyLinkedList<class RawSocket> RawSocketList;
class RawSocket : public DoublyLinkedListLinkImpl<RawSocket> { class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
public: public:
RawSocket(net_socket *socket); RawSocket(net_socket *socket);
~RawSocket();
status_t InitCheck();
status_t Read(size_t numBytes, uint32 flags, bigtime_t timeout,
net_buffer **_buffer);
ssize_t BytesAvailable();
status_t Write(net_buffer *buffer);
private:
net_socket *fSocket;
net_fifo fFifo;
}; };
struct ipv4_protocol : net_protocol { struct ipv4_protocol : net_protocol {
@@ -142,10 +130,11 @@ struct ipv4_protocol : net_protocol {
extern net_protocol_module_info gIPv4Module; extern net_protocol_module_info gIPv4Module;
// we need this in ipv4_std_ops() for registering the AF_INET domain // we need this in ipv4_std_ops() for registering the AF_INET domain
net_stack_module_info *gStackModule;
net_buffer_module_info *gBufferModule;
static struct net_domain *sDomain; static struct net_domain *sDomain;
static net_datalink_module_info *sDatalinkModule; static net_datalink_module_info *sDatalinkModule;
static net_stack_module_info *sStackModule;
struct net_buffer_module_info *gBufferModule;
static int32 sPacketID; static int32 sPacketID;
static RawSocketList sRawSockets; static RawSocketList sRawSockets;
static benaphore sRawSocketsLock; static benaphore sRawSocketsLock;
@@ -156,56 +145,8 @@ static benaphore sReceivingProtocolLock;
RawSocket::RawSocket(net_socket *socket) RawSocket::RawSocket(net_socket *socket)
: : DatagramSocket<>("ipv4 raw socket", socket)
fSocket(socket)
{ {
status_t status = sStackModule->init_fifo(&fFifo, "ipv4 raw socket", 65536);
if (status < B_OK)
fFifo.notify = status;
}
RawSocket::~RawSocket()
{
if (fFifo.notify >= B_OK)
sStackModule->uninit_fifo(&fFifo);
}
status_t
RawSocket::InitCheck()
{
return fFifo.notify >= B_OK ? B_OK : fFifo.notify;
}
status_t
RawSocket::Read(size_t numBytes, uint32 flags, bigtime_t timeout,
net_buffer **_buffer)
{
net_buffer *buffer;
status_t status = sStackModule->fifo_dequeue_buffer(&fFifo,
flags, timeout, &buffer);
if (status < B_OK)
return status;
*_buffer = buffer;
return B_OK;
}
ssize_t
RawSocket::BytesAvailable()
{
return fFifo.current_bytes;
}
status_t
RawSocket::Write(net_buffer *source)
{
return sStackModule->fifo_socket_enqueue_buffer(&fFifo, fSocket,
B_SELECT_READ, source);
} }
@@ -218,14 +159,14 @@ FragmentPacket::FragmentPacket(const ipv4_packet_key &key)
fReceivedLastFragment(false), fReceivedLastFragment(false),
fBytesLeft(IP_MAXPACKET) fBytesLeft(IP_MAXPACKET)
{ {
sStackModule->init_timer(&fTimer, StaleTimer, this); gStackModule->init_timer(&fTimer, StaleTimer, this);
} }
FragmentPacket::~FragmentPacket() FragmentPacket::~FragmentPacket()
{ {
// cancel the kill timer // cancel the kill timer
sStackModule->set_timer(&fTimer, -1); gStackModule->set_timer(&fTimer, -1);
// delete all fragments // delete all fragments
net_buffer *buffer; net_buffer *buffer;
@@ -240,7 +181,7 @@ FragmentPacket::AddFragment(uint16 start, uint16 end, net_buffer *buffer,
bool lastFragment) bool lastFragment)
{ {
// restart the timer // restart the timer
sStackModule->set_timer(&fTimer, FRAGMENT_TIMEOUT); gStackModule->set_timer(&fTimer, FRAGMENT_TIMEOUT);
if (start >= end) { if (start >= end) {
// invalid fragment // invalid fragment
@@ -595,7 +536,7 @@ send_fragments(ipv4_protocol *protocol, struct net_route *route,
header->fragment_offset = htons((lastFragment ? 0 : IP_MORE_FRAGMENTS) header->fragment_offset = htons((lastFragment ? 0 : IP_MORE_FRAGMENTS)
| (fragmentOffset >> 3)); | (fragmentOffset >> 3));
header->checksum = 0; header->checksum = 0;
header->checksum = sStackModule->checksum((uint8 *)header, headerLength); header->checksum = gStackModule->checksum((uint8 *)header, headerLength);
// TODO: compute the checksum only for those parts that changed? // TODO: compute the checksum only for those parts that changed?
dprintf(" send fragment of %ld bytes (%ld bytes left)\n", fragmentLength, bytesLeft); dprintf(" send fragment of %ld bytes (%ld bytes left)\n", fragmentLength, bytesLeft);
@@ -644,10 +585,8 @@ raw_receive_data(net_buffer *buffer)
RawSocketList::Iterator iterator = sRawSockets.GetIterator(); RawSocketList::Iterator iterator = sRawSockets.GetIterator();
while (iterator.HasNext()) { while (iterator.HasNext())
RawSocket *raw = iterator.Next(); iterator.Next()->EnqueueClone(buffer);
raw->Write(buffer);
}
} }
@@ -664,7 +603,7 @@ receiving_protocol(uint8 protocol)
if (module != NULL) if (module != NULL)
return module; return module;
if (sStackModule->get_domain_receiving_protocol(sDomain, protocol, &module) == B_OK) if (gStackModule->get_domain_receiving_protocol(sDomain, protocol, &module) == B_OK)
sReceivingProtocol[protocol] = module; sReceivingProtocol[protocol] = module;
return module; return module;
@@ -1016,7 +955,7 @@ ipv4_read_data(net_protocol *_protocol, size_t numBytes, uint32 flags,
return B_ERROR; return B_ERROR;
TRACE(("read is waiting for data...\n")); TRACE(("read is waiting for data...\n"));
return raw->Read(numBytes, flags, protocol->socket->receive.timeout, _buffer); return raw->SocketDequeue(flags, _buffer);
} }
@@ -1028,7 +967,7 @@ ipv4_read_avail(net_protocol *_protocol)
if (raw == NULL) if (raw == NULL)
return B_ERROR; return B_ERROR;
return raw->BytesAvailable(); return raw->AvailableData();
} }
@@ -1175,7 +1114,7 @@ ipv4_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
status_t status_t
init_ipv4() init_ipv4()
{ {
status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule); status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&gStackModule);
if (status < B_OK) if (status < B_OK)
return status; return status;
status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
@@ -1209,12 +1148,12 @@ init_ipv4()
// so we have to do it here, manually // so we have to do it here, manually
// TODO: for modules, this shouldn't be required // TODO: for modules, this shouldn't be required
status = sStackModule->register_domain_protocols(AF_INET, SOCK_RAW, 0, status = gStackModule->register_domain_protocols(AF_INET, SOCK_RAW, 0,
"network/protocols/ipv4/v1", NULL); "network/protocols/ipv4/v1", NULL);
if (status < B_OK) if (status < B_OK)
goto err7; goto err7;
status = sStackModule->register_domain(AF_INET, "internet", &gIPv4Module, status = gStackModule->register_domain(AF_INET, "internet", &gIPv4Module,
&gIPv4AddressModule, &sDomain); &gIPv4AddressModule, &sDomain);
if (status < B_OK) if (status < B_OK)
goto err7; goto err7;
@@ -1247,10 +1186,10 @@ uninit_ipv4()
// put all the domain receiving protocols we gathered so far // put all the domain receiving protocols we gathered so far
for (uint32 i = 0; i < 256; i++) { for (uint32 i = 0; i < 256; i++) {
if (sReceivingProtocol[i] != NULL) if (sReceivingProtocol[i] != NULL)
sStackModule->put_domain_receiving_protocol(sDomain, i); gStackModule->put_domain_receiving_protocol(sDomain, i);
} }
sStackModule->unregister_domain(sDomain); gStackModule->unregister_domain(sDomain);
benaphore_unlock(&sReceivingProtocolLock); benaphore_unlock(&sReceivingProtocolLock);
hash_uninit(sFragmentHash); hash_uninit(sFragmentHash);
@@ -22,6 +22,7 @@
#include <NetBufferUtilities.h> #include <NetBufferUtilities.h>
#include <NetUtilities.h> #include <NetUtilities.h>
#include <ProtocolUtilities.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <new> #include <new>
@@ -29,9 +30,6 @@
#include <string.h> #include <string.h>
#include <utility> #include <utility>
// TODO move the locking from the FIFO to the whole Endpoint
// much like we did with the LinkProtocol.
//#define TRACE_UDP //#define TRACE_UDP
#ifdef TRACE_UDP #ifdef TRACE_UDP
# define TRACE_BLOCK(x) dump_block x # define TRACE_BLOCK(x) dump_block x
@@ -64,12 +62,9 @@ typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
class UdpDomainSupport; class UdpDomainSupport;
class UdpEndpoint : public net_protocol { class UdpEndpoint : public net_protocol, public DatagramSocket<> {
public: public:
UdpEndpoint(net_socket *socket); UdpEndpoint(net_socket *socket);
~UdpEndpoint();
status_t InitCheck() const;
status_t Bind(sockaddr *newAddr); status_t Bind(sockaddr *newAddr);
status_t Unbind(sockaddr *newAddr); status_t Unbind(sockaddr *newAddr);
@@ -110,8 +105,6 @@ private:
bool fActive; bool fActive;
// an active UdpEndpoint is part of the endpoint // an active UdpEndpoint is part of the endpoint
// hash (and it is bound and optionally connected) // hash (and it is bound and optionally connected)
net_fifo fFifo;
// storage space for incoming data
}; };
@@ -208,9 +201,9 @@ private:
static UdpEndpointManager *sUdpEndpointManager; static UdpEndpointManager *sUdpEndpointManager;
net_stack_module_info *gStackModule;
net_buffer_module_info *gBufferModule; net_buffer_module_info *gBufferModule;
static net_datalink_module_info *sDatalinkModule; static net_datalink_module_info *sDatalinkModule;
static net_stack_module_info *sStackModule;
// #pragma mark - // #pragma mark -
@@ -707,27 +700,10 @@ UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
UdpEndpoint::UdpEndpoint(net_socket *socket) UdpEndpoint::UdpEndpoint(net_socket *socket)
: :
DatagramSocket<>("udp endpoint", socket),
fDomain(NULL), fDomain(NULL),
fActive(false) fActive(false)
{ {
status_t status = sStackModule->init_fifo(&fFifo, "UDP endpoint fifo",
socket->receive.buffer_size);
if (status < B_OK)
fFifo.notify = status;
}
UdpEndpoint::~UdpEndpoint()
{
if (fFifo.notify >= B_OK)
sStackModule->uninit_fifo(&fFifo);
}
status_t
UdpEndpoint::InitCheck() const
{
return fFifo.notify;
} }
@@ -945,9 +921,9 @@ UdpEndpoint::SendData(net_buffer *buffer)
ssize_t ssize_t
UdpEndpoint::BytesAvailable() UdpEndpoint::BytesAvailable()
{ {
// TODO protect this call size_t bytes = AvailableData();
TRACE_EP("BytesAvailable(): %lu", fFifo.current_bytes); TRACE_EP("BytesAvailable(): %lu", bytes);
return fFifo.current_bytes; return bytes;
} }
@@ -956,16 +932,12 @@ UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
{ {
TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags); TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags);
net_buffer *buffer; status_t status = SocketDequeue(flags, _buffer);
status_t status = sStackModule->fifo_dequeue_buffer(&fFifo, flags,
socket->receive.timeout, &buffer);
TRACE_EP(" FetchData(): returned from fifo status=0x%lx", status); TRACE_EP(" FetchData(): returned from fifo status=0x%lx", status);
if (status < B_OK) if (status < B_OK)
return status; return status;
TRACE_EP(" FetchData(): returns buffer with %ld bytes", buffer->size); TRACE_EP(" FetchData(): returns buffer with %ld bytes", (*_buffer)->size);
*_buffer = buffer;
return B_OK; return B_OK;
} }
@@ -975,8 +947,7 @@ UdpEndpoint::StoreData(net_buffer *buffer)
{ {
TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size); TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size);
return sStackModule->fifo_socket_enqueue_buffer(&fFifo, socket, return EnqueueClone(buffer);
B_SELECT_READ, buffer);
} }
@@ -1160,7 +1131,7 @@ init_udp()
status_t status; status_t status;
TRACE_EPM("init_udp()"); TRACE_EPM("init_udp()");
status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule); status = get_module(NET_STACK_MODULE_NAME, (module_info **)&gStackModule);
if (status < B_OK) if (status < B_OK)
return status; return status;
status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
@@ -1179,20 +1150,20 @@ init_udp()
if (status != B_OK) if (status != B_OK)
goto err3; goto err3;
status = sStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP, status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP,
"network/protocols/udp/v1", "network/protocols/udp/v1",
"network/protocols/ipv4/v1", "network/protocols/ipv4/v1",
NULL); NULL);
if (status < B_OK) if (status < B_OK)
goto err4; goto err4;
status = sStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP, status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
"network/protocols/udp/v1", "network/protocols/udp/v1",
"network/protocols/ipv4/v1", "network/protocols/ipv4/v1",
NULL); NULL);
if (status < B_OK) if (status < B_OK)
goto err4; goto err4;
status = sStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP, status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP,
"network/protocols/udp/v1"); "network/protocols/udp/v1");
if (status < B_OK) if (status < B_OK)
goto err4; goto err4;
+28 -46
View File
@@ -20,6 +20,7 @@
#include <util/AutoLock.h> #include <util/AutoLock.h>
#include <KernelExport.h> #include <KernelExport.h>
#include <ProtocolUtilities.h>
#include <net/if_types.h> #include <net/if_types.h>
#include <new> #include <new>
@@ -28,12 +29,18 @@
#include <sys/sockio.h> #include <sys/sockio.h>
class LinkProtocol : public net_protocol { class LocalStackBundle {
public: public:
LinkProtocol(); static net_stack_module_info *Stack() { return &gNetStackModule; }
~LinkProtocol(); static net_buffer_module_info *Buffer() { return &gNetBufferModule; }
};
status_t InitCheck() const; typedef DatagramSocket<BenaphoreLocking, LocalStackBundle> LocalDatagramSocket;
class LinkProtocol : public net_protocol, public LocalDatagramSocket {
public:
LinkProtocol(net_socket *socket);
~LinkProtocol();
status_t StartMonitoring(const char *); status_t StartMonitoring(const char *);
status_t StopMonitoring(); status_t StopMonitoring();
@@ -42,12 +49,8 @@ public:
ssize_t ReadAvail() const; ssize_t ReadAvail() const;
private: private:
status_t _Enqueue(net_buffer *buffer);
status_t _Unregister(); status_t _Unregister();
mutable benaphore fLock;
Fifo fFifo;
net_device_monitor fMonitor; net_device_monitor fMonitor;
net_device_interface *fMonitoredDevice; net_device_interface *fMonitoredDevice;
@@ -59,11 +62,9 @@ private:
struct net_domain *sDomain; struct net_domain *sDomain;
LinkProtocol::LinkProtocol() LinkProtocol::LinkProtocol(net_socket *socket)
: fFifo("packet monitor fifo", 65536) : LocalDatagramSocket("packet capture", socket)
{ {
benaphore_init(&fLock, "packet monitor lock");
fMonitor.cookie = this; fMonitor.cookie = this;
fMonitor.receive = _MonitorData; fMonitor.receive = _MonitorData;
fMonitor.event = _MonitorEvent; fMonitor.event = _MonitorEvent;
@@ -77,15 +78,6 @@ LinkProtocol::~LinkProtocol()
unregister_device_monitor(fMonitoredDevice->device, &fMonitor); unregister_device_monitor(fMonitoredDevice->device, &fMonitor);
put_device_interface(fMonitoredDevice); put_device_interface(fMonitoredDevice);
} }
benaphore_destroy(&fLock);
}
status_t
LinkProtocol::InitCheck() const
{
return fLock.sem >= 0 && fFifo.InitCheck();
} }
@@ -127,26 +119,24 @@ LinkProtocol::ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer)
{ {
BenaphoreLocker _(fLock); BenaphoreLocker _(fLock);
bigtime_t timeout = socket->receive.timeout; bool clone = flags & MSG_PEEK;
bigtime_t timeout = _SocketTimeout(flags);
if (timeout == 0) bool waited = false;
flags |= MSG_DONTWAIT; while (_IsEmpty()) {
else if (timeout != B_INFINITE_TIMEOUT)
timeout += system_time();
while (fFifo.IsEmpty()) {
if (fMonitoredDevice == NULL) if (fMonitoredDevice == NULL)
return ENODEV; return ENODEV;
status_t status = B_WOULD_BLOCK; status_t status = _Wait(timeout);
if ((flags & MSG_DONTWAIT) == 0)
status = fFifo.Wait(&fLock, timeout);
if (status < B_OK) if (status < B_OK)
return status; return status;
waited = true;
} }
*_buffer = fFifo.Dequeue(flags & MSG_PEEK); *_buffer = _Dequeue(clone);
if (clone && waited)
_NotifyOneReader(false);
return *_buffer ? B_OK : B_NO_MEMORY; return *_buffer ? B_OK : B_NO_MEMORY;
} }
@@ -157,7 +147,7 @@ LinkProtocol::ReadAvail() const
BenaphoreLocker _(fLock); BenaphoreLocker _(fLock);
if (fMonitoredDevice == NULL) if (fMonitoredDevice == NULL)
return ENODEV; return ENODEV;
return fFifo.current_bytes; return fCurrentBytes;
} }
@@ -176,18 +166,10 @@ LinkProtocol::_Unregister()
} }
status_t
LinkProtocol::_Enqueue(net_buffer *buffer)
{
BenaphoreLocker _(fLock);
return fFifo.EnqueueAndNotify(buffer, socket, B_SELECT_READ);
}
status_t status_t
LinkProtocol::_MonitorData(net_device_monitor *monitor, net_buffer *packet) LinkProtocol::_MonitorData(net_device_monitor *monitor, net_buffer *packet)
{ {
return ((LinkProtocol *)monitor->cookie)->_Enqueue(packet); return ((LinkProtocol *)monitor->cookie)->EnqueueClone(packet);
} }
@@ -200,8 +182,8 @@ LinkProtocol::_MonitorEvent(net_device_monitor *monitor, int32 event)
BenaphoreLocker _(protocol->fLock); BenaphoreLocker _(protocol->fLock);
protocol->_Unregister(); protocol->_Unregister();
if (protocol->fFifo.IsEmpty()) { if (protocol->_IsEmpty()) {
protocol->fFifo.WakeAll(); protocol->WakeAll();
notify_socket(protocol->socket, B_SELECT_READ, ENODEV); notify_socket(protocol->socket, B_SELECT_READ, ENODEV);
} }
} }
@@ -214,7 +196,7 @@ LinkProtocol::_MonitorEvent(net_device_monitor *monitor, int32 event)
net_protocol * net_protocol *
link_init_protocol(net_socket *socket) link_init_protocol(net_socket *socket)
{ {
LinkProtocol *protocol = new (std::nothrow) LinkProtocol(); LinkProtocol *protocol = new (std::nothrow) LinkProtocol(socket);
if (protocol && protocol->InitCheck() < B_OK) { if (protocol && protocol->InitCheck() < B_OK) {
delete protocol; delete protocol;
return NULL; return NULL;
+2 -2
View File
@@ -888,7 +888,7 @@ stack_std_ops(int32 op, ...)
} }
static net_stack_module_info sNetStackModule = { net_stack_module_info gNetStackModule = {
{ {
NET_STACK_MODULE_NAME, NET_STACK_MODULE_NAME,
0, 0,
@@ -939,7 +939,7 @@ static module_info sNetStarterModule = {
}; };
module_info *modules[] = { module_info *modules[] = {
(module_info *)&sNetStackModule, (module_info *)&gNetStackModule,
(module_info *)&sNetStarterModule, (module_info *)&sNetStarterModule,
(module_info *)&gNetBufferModule, (module_info *)&gNetBufferModule,
(module_info *)&gNetSocketModule, (module_info *)&gNetSocketModule,
@@ -14,10 +14,12 @@
#include <net_datalink_protocol.h> #include <net_datalink_protocol.h>
#include <net_protocol.h> #include <net_protocol.h>
#include <net_socket.h> #include <net_socket.h>
#include <net_stack.h>
#define NET_STARTER_MODULE_NAME "network/stack/starter/v1" #define NET_STARTER_MODULE_NAME "network/stack/starter/v1"
extern net_stack_module_info gNetStackModule;
extern net_buffer_module_info gNetBufferModule; extern net_buffer_module_info gNetBufferModule;
extern net_socket_module_info gNetSocketModule; extern net_socket_module_info gNetSocketModule;
extern net_datalink_module_info gNetDatalinkModule; extern net_datalink_module_info gNetDatalinkModule;