[jitsi-dev] Socket listener implementation (|ice4j)


#1

Hi list!

  The question is about ice4j

  I try to listen everything that going on my socket, so I do
something like this:

socket = localAgent.getStream("audio").getComponent(1).getSelectedPair().getLocalCandidate().getSocket();
remoteAddress =
localAgent.getStream("audio").getComponent(1).getSelectedPair().getRemoteCandidate().getTransportAddress();

Than something like this :

while (doIt){
  DatagrammPacket p = new DatagrammPacket(new byte[4096], 4096);
  socket.receive(p);
}

I get messages, everything ok - except the one - When I start transmit
raw audio data (big size of data) I got memory leak.
I look into MulteplexingDatagrammSocket.java and saw this:

                            for (MultiplexedDatagramSocket socket : sockets)
                                if (socket.getFilter().accept(p))
                                {
                                    socket.received.add(clone(p));
                                    accepted = true;

You add to the received but never remove from there.

Or may be I should implement Listener somehow else? Just show me where to dig.

Thank you.


#2

Hi,

Hi list!

   The question is about ice4j

   I try to listen everything that going on my socket, so I do
something like this:

socket = localAgent.getStream("audio").getComponent(1).getSelectedPair().getLocalCandidate().getSocket();
remoteAddress =
localAgent.getStream("audio").getComponent(1).getSelectedPair().getRemoteCandidate().getTransportAddress();

Than something like this :

while (doIt){
   DatagrammPacket p = new DatagrammPacket(new byte[4096], 4096);
   socket.receive(p);
}

I get messages, everything ok - except the one - When I start transmit
raw audio data (big size of data) I got memory leak.
I look into MulteplexingDatagrammSocket.java and saw this:

                             for (MultiplexedDatagramSocket socket : sockets)
                                 if (socket.getFilter().accept(p))
                                 {
                                     socket.received.add(clone(p));
                                     accepted = true;

You add to the received but never remove from there.

I don't think it is kept in the socket. It is removed from "received" when you read on the socket (see MultiplexedDatagram.receive(DatagramPacket p) method).

When you say "I got memory leak", you mean OutOfMemoryException ?

In your code, do you call LocalCandidate's getStunSocket(...) or ConnectivityCheckClient's startChecksForPair(...) methods ?

Regards,

···

Le 08/06/11 08:46, Андрей Сергеевич Дидух a écrit :
--
Seb

Or may be I should implement Listener somehow else? Just show me where to dig.

Thank you.


#3

Hi Sebastien,

When you say "I got memory leak", you mean OutOfMemoryException ?

Yes, OutOfMemoryException - in the clone of packet for revived.add.
(Almost 160Mb, than all freezes).

In your code, do you call LocalCandidate's getStunSocket(...) or ConnectivityCheckClient's startChecksForPair(...) methods ?

I dont think so, what I do - is just:

localAgent = createAgent(somePort);
localAgent.setControlling(false); //or true depends which cluent I run

//than I pass sdp of another client into our local (I get this from
test packages of ice4j)
SdpUtils.parseSDP(localAgent, sdp);
localAgent.startConnectivityEstablishment();

Than I "listen", as I show before.

Thank you for reply.


#4

By the way - if I not do socket.receive(p); - I also got OutOfMemory.


#5

As I understand - all datagrams that was not catched by any
DatagrammFilter stored in recived buffer forever...

Am I wrong? Cuz I see :

r = received.remove(0); //line 403 in MulteplexingDatagrammSocket.java

But this for Multplexing, and nothing like this for Multeplexed.


#6

From another side - in MultiplexedDatagramSocket.recive stored only

that what accepted by filter...


#7

The current implementation of Miltiplexed/MultiplexingDatagramSocket
relies on all data being read/received out of it and it's a known
problem that, if one fails to do so, an out-of-memory scenario will be
entered. In other words, you should either read/receive both filtered
and filtered packets as they come or an improvement/strategy should be
implemented to drop unread/unreceived packets. Please feel free to
contribute code on the latter subject.


#8

1)
What if I implement something like stack, lets say for 100 Datagramms
for this List<Datagramm> recived? For Multeplexed and Multeplexing
classes respectively.

Is this fix problem, or I just broke smthg. ?

2)
How can I "drop" recived datagramms from filter?? I 'm not create
additional filters, only that what in Agent.java ...


#9

1)
What if I implement something like stack, lets say for 100 Datagramms
for this List<Datagramm> recived? For Multeplexed and Multeplexing
classes respectively.

"100 Datagrams" is really the heart of the strategy, I think. I'm not
sure a fixed number of datagram packets is a good approach. Shouldn't
we rather be basing our decision based on DatagramSocket's
receiveBufferSize property?

2)
How can I "drop" recived datagramms from filter?? I 'm not create
additional filters, only that what in Agent.java ...

Both Multipled and MultiplexingDatagramSocket have their own #received
List<DatagramPacket> which retains the received datagram packets until
the Java heap runs out of memory (or they are read out, of course).
When we come up with a strategy which is to drop datagram packets in
order to prevent the out-of-memory scenario, we'll just remove a
certain number of datagram packets from #received before adding a new
one, I guess.

···

On Wed, Jun 8, 2011 at 6:08 PM, Андрей Сергеевич Дидух <tower120@gmail.com> wrote:


#10

Shouldn't we rather be basing our decision based on DatagramSocket's

receiveBufferSize property?

DatagramSocket's receiveBufferSize property returns BYTES, not
Datagramms. We talk about datagramms, in each datagramm can by
DatagramSocket.receiveBufferSize bytes. Or am I mistaken?

Both Multipled and MultiplexingDatagramSocket have their own #received

List<DatagramPacket> which retains the received datagram packets until
the Java heap runs out of memory (or they are read out, of course).
When we come up with a strategy which is to drop datagram packets in
order to prevent the out-of-memory scenario, we'll just remove a
certain number of datagram packets from #received before adding a new
one, I guess.

Than I implement my idea with limited stack of received :slight_smile:

I'll commit it when its done.


#11

Hey Андрей,

На 08.06.11 21:03, Андрей Сергеевич Дидух написа:

Shouldn't we rather be basing our decision based on DatagramSocket's

receiveBufferSize property?

DatagramSocket's receiveBufferSize property returns BYTES, not
Datagramms.

Which is all the more reason not to use a specific number of datagrams
as a basis for the decision.

We talk about datagramms, in each datagramm can by
DatagramSocket.receiveBufferSize bytes. Or am I mistaken?

Both Multipled and MultiplexingDatagramSocket have their own #received

List<DatagramPacket> which retains the received datagram packets until
the Java heap runs out of memory (or they are read out, of course).
When we come up with a strategy which is to drop datagram packets in
order to prevent the out-of-memory scenario, we'll just remove a
certain number of datagram packets from #received before adding a new
one, I guess.

Than I implement my idea with limited stack of received :slight_smile:

I'll commit it when its done.

Commit access to ice4j is subject to the same rules as Jitsi [0] and is
only granted to team members and confirmed contributors. This means that
you'll first have to participate in mailing list discussions and submit
some fixes, patches, or other contributions before being accepted as a
developer in the project.

We would of course be happy to integrate a patch from you but in order
for that to happen it would need to comply with the project requirements
and follow the guidelines that developers (like Lyubomir) are giving to you.

Also, just so that I am clear, you do realize that dropping packets in
case of an overflow is simply a corner case, right? The other obvious,
solution, and main use case, would be for you to simply receive() these
packets since that is, after all, the main purpose of using a socket.

Cheers,
Emil

[0] Becoming a Jitsi Committer -
http://www.jitsi.org/index.php/Documentation/CommitAccess


#12

From: Emil Ivov <emcho@jitsi.org>

Hey there,

Could you please send your reply to the list so that others interested
in the discussion could also follow?

Thanks,
Emil

На 08.06.11 21:20, Андрей Сергеевич Дидух написа:

···

---------- Forwarded message ----------
Date: 2011/6/8
Subject: Re: [jitsi-dev] Re: Socket listener implementation (|ice4j)
To: Андрей Сергеевич Дидух <tower120@gmail.com>

Hi Emil,

As I wrote before, i DO recive() absolutlty evrything from that
socket. BUT I can't recive packets from StunFilter and TurnFilter.


#13

As far as I understand the Javadoc of
DatagramSocket#setReceiveBufferSize(int) by just reading it (and not
testing it), it sets SO_RCVBUF which hints to the operating system
that it should size its underlying I/O buffers accordingly and "may
allow the network implementation to buffer multiple packets when
packets arrive faster than are being received using #receive()."

Anyway, 100 DatagramPackets may still occupy less bytes than 50
DatagramPackets carrying a larger payload so I still think we should
be basing our decision based on bytes, not on DatagramPacket count
only.

···

On Wed, Jun 8, 2011 at 10:03 PM, Андрей Сергеевич Дидух <tower120@gmail.com> wrote:

Shouldn't we rather be basing our decision based on DatagramSocket's

receiveBufferSize property?

DatagramSocket's receiveBufferSize property returns BYTES, not
Datagramms. We talk about datagramms, in each datagramm can by
DatagramSocket.receiveBufferSize bytes. Or am I mistaken?


#14

Hi Emil,

As I wrote before, i DO recive() absolutlty evrything from that
socket. BUT I can't recive packets from StunFilter and TurnFilter.


#15

Ok, I understand your point of view.

Just one sec, I'll change it.


#16

And even if I this is NOT corner case - I think that use unlimmited
recive buffer is not correct.


#17

Hmmm, no - I think its imposible. We dont know packet size
,beforehand. Moreover it can change.

So I can't just do this to calculate recived size :

this.getReceiveBufferSize() / p.getLength()

Such as we do this ONLY to prevent OutOfMemory error I think we may
set MAX_RECIVED_BUFFER_SIZE not to 100, but, let's say 1000. Its take
not more than 8Mb when packet size 8Kb.


#18

Emil,

  I tried to limit recived - and it works perfect to me. But I don't
understand why you want to use receiveBufferSize instead of fixed
number of datagramms? How we should calculate size of recived buffer
then?


#19

I finally found the reason of memory leaks. That was because
StunDatagamFilter catch most of my packets with raw audio data. I was
very surprised when I saw that stun packets have no some signature at
the begin, just 00 bits in first byte. But I think that many of the
packets may begins from this.

The solution for me becomes adding byte 0x11 before my data packet.


#20

It is difficult to me to make patch - so I just attach files that I change.

MultiplexingDatagramSocket.java (16.5 KB)

DelegatingDatagramSocket.java (23.7 KB)