* deliver_multicast() now returns whether or not it delivered the buffer,

instead of always returning B_OK.
* deliver_multicast() now takes the protocol restriction of a raw socket into
  account.
* raw_receive_data() now correctly returns whether a buffer was delivered (due
  to the protocol restriction, this wasn't the case before).
* ipv4_receive_data() leaked all multicast buffers.
* Some minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37648 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-07-21 13:11:58 +00:00
parent 1978fb81ee
commit aea00dc3bc
@@ -69,37 +69,38 @@ struct ipv4_packet_key {
class FragmentPacket { class FragmentPacket {
public: public:
FragmentPacket(const ipv4_packet_key &key); FragmentPacket(const ipv4_packet_key& key);
~FragmentPacket(); ~FragmentPacket();
status_t AddFragment(uint16 start, uint16 end, status_t AddFragment(uint16 start, uint16 end,
net_buffer* buffer, bool lastFragment); net_buffer* buffer, bool lastFragment);
status_t Reassemble(net_buffer* to); status_t Reassemble(net_buffer* to);
bool IsComplete() const bool IsComplete() const
{ return fReceivedLastFragment { return fReceivedLastFragment
&& fBytesLeft == 0; } && fBytesLeft == 0; }
static uint32 Hash(void* _packet, const void* _key, uint32 range); static uint32 Hash(void* _packet, const void* _key,
static int Compare(void* _packet, const void* _key); uint32 range);
static int32 NextOffset() static int Compare(void* _packet, const void* _key);
{ return offsetof(FragmentPacket, fNext); } static int32 NextOffset()
static void StaleTimer(struct net_timer* timer, void* data); { return offsetof(FragmentPacket, fNext); }
static void StaleTimer(struct net_timer* timer, void* data);
private: private:
FragmentPacket* fNext; FragmentPacket* fNext;
struct ipv4_packet_key fKey; struct ipv4_packet_key fKey;
bool fReceivedLastFragment; bool fReceivedLastFragment;
int32 fBytesLeft; int32 fBytesLeft;
FragmentList fFragments; FragmentList fFragments;
net_timer fTimer; net_timer fTimer;
}; };
class RawSocket class RawSocket
: public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> { : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
public: public:
RawSocket(net_socket* socket); RawSocket(net_socket* socket);
}; };
typedef DoublyLinkedList<RawSocket> RawSocketList; typedef DoublyLinkedList<RawSocket> RawSocketList;
@@ -133,14 +134,14 @@ struct ipv4_protocol : net_protocol {
{ {
} }
RawSocket *raw; RawSocket* raw;
uint8 service_type; uint8 service_type;
uint8 time_to_live; uint8 time_to_live;
uint8 multicast_time_to_live; uint8 multicast_time_to_live;
uint32 flags; uint32 flags;
struct sockaddr* interface_address; // for IP_MULTICAST_IF struct sockaddr* interface_address; // for IP_MULTICAST_IF
IPv4MulticastFilter multicast_filter; IPv4MulticastFilter multicast_filter;
}; };
// protocol flags // protocol flags
@@ -660,12 +661,15 @@ send_fragments(ipv4_protocol* protocol, struct net_route* route,
} }
static status_t /*! Delivers the provided \a buffer to all listeners of this multicast group.
Does not take over ownership of the buffer.
*/
static bool
deliver_multicast(net_protocol_module_info* module, net_buffer* buffer, deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
bool deliverToRaw) bool deliverToRaw)
{ {
if (module->deliver_data == NULL) if (module->deliver_data == NULL)
return B_OK; return false;
MutexLocker _(sMulticastGroupsLock); MutexLocker _(sMulticastGroupsLock);
@@ -674,32 +678,41 @@ deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair( MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair(
&multicastAddr->sin_addr, buffer->interface->index)); &multicastAddr->sin_addr, buffer->interface->index));
size_t count = 0;
while (it.HasNext()) { while (it.HasNext()) {
IPv4GroupInterface* state = it.Next(); IPv4GroupInterface* state = it.Next();
if (deliverToRaw && state->Parent()->Socket()->raw == NULL) ipv4_protocol* ipProtocol = state->Parent()->Socket();
if (deliverToRaw && (ipProtocol->raw == NULL
|| ipProtocol->socket->protocol != buffer->protocol))
continue; continue;
if (state->FilterAccepts(buffer)) { if (state->FilterAccepts(buffer)) {
// as Multicast filters are installed with an IPv4 protocol net_protocol* protocol = ipProtocol;
// reference, we need to go and find the appropriate instance if (protocol->module != module) {
// related to the 'receiving protocol' with module 'module'. // as multicast filters are installed with an IPv4 protocol
net_protocol* protocol // reference, we need to go and find the appropriate instance
= state->Parent()->Socket()->socket->first_protocol; // related to the 'receiving protocol' with module 'module'.
net_protocol* protocol = ipProtocol->socket->first_protocol;
while (protocol != NULL && protocol->module != module) while (protocol != NULL && protocol->module != module)
protocol = protocol->next; protocol = protocol->next;
}
if (protocol != NULL) if (protocol != NULL) {
module->deliver_data(protocol, buffer); module->deliver_data(protocol, buffer);
count++;
}
} }
} }
return B_OK; return count > 0;
} }
/*! Delivers the buffer to all listening raw sockets. /*! Delivers the buffer to all listening raw sockets without taking ownership of
the provided \a buffer.
Returns \c true if there was any receiver, \c false if not. Returns \c true if there was any receiver, \c false if not.
*/ */
static bool static bool
@@ -712,25 +725,28 @@ raw_receive_data(net_buffer* buffer)
TRACE("RawReceiveData(%i)", buffer->protocol); TRACE("RawReceiveData(%i)", buffer->protocol);
if (buffer->flags & MSG_MCAST) { if ((buffer->flags & MSG_MCAST) != 0) {
// we need to call deliver_multicast here separately as // we need to call deliver_multicast here separately as
// buffer still has the IP header, and it won't in the // buffer still has the IP header, and it won't in the
// next call. This isn't very optimized but works for now. // next call. This isn't very optimized but works for now.
// A better solution would be to hold separate hash tables // A better solution would be to hold separate hash tables
// and lists for RAW and non-RAW sockets. // and lists for RAW and non-RAW sockets.
deliver_multicast(&gIPv4Module, buffer, true); return deliver_multicast(&gIPv4Module, buffer, true);
} else { }
RawSocketList::Iterator iterator = sRawSockets.GetIterator();
RawSocketList::Iterator iterator = sRawSockets.GetIterator();
size_t count = 0;
while (iterator.HasNext()) { while (iterator.HasNext()) {
RawSocket* raw = iterator.Next(); RawSocket* raw = iterator.Next();
if (raw->Socket()->protocol == buffer->protocol) if (raw->Socket()->protocol == buffer->protocol) {
raw->SocketEnqueue(buffer); raw->SocketEnqueue(buffer);
count++;
} }
} }
return true; return count > 0;
} }
@@ -1637,11 +1653,13 @@ ipv4_receive_data(net_buffer* buffer)
} }
if ((buffer->flags & MSG_MCAST) != 0) { if ((buffer->flags & MSG_MCAST) != 0) {
// Unfortunely historical reasons dictate that the IP multicast // Unfortunately historical reasons dictate that the IP multicast
// model be a little different from the unicast one. We deliver // model be a little different from the unicast one. We deliver
// this frame directly to all sockets registered with interest // this frame directly to all sockets registered with interest
// for this multicast group. // for this multicast group.
return deliver_multicast(module, buffer, false); deliver_multicast(module, buffer, false);
gBufferModule->free(buffer);
return B_OK;
} }
return module->receive_data(buffer); return module->receive_data(buffer);