Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2012-05

I need an lNet expert: multiple connections and only one central CallAction() - is this possible?

5 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bernd

This is a pure fpc project, no LCL. If I have understood it correctly then I have to call the CallAction() method for every connection I have created but this seems to totally contradict what it claims to be able to do: namely using some sophisticated event-mechanism that can watch multiple handles at the same time.

What I have currently been doing is (without lNet or any other framework) simply using one thread for each potentially blocking call. This means I had one thread for each listening port blocking in fpaccept(), one thread for each connection attempt blocking in connect (or waiting for the socks4 proxy), and one thread for each connection blocking in fprecv(). This makes the code really simple but causes a lot of other problems.

Now I have read that lNet is able to use sophisticated stuff like ePoll (if available) or other such mechanisms for asynchronous sockets but I cannot find any example where this is actually done. The examples just use one connection and then CallAction() on this connection and If I wanted to do this with multiple connections I would again end up with one thread per connection blocking in the CallAction of its connection object. Obviously I am missing something here?

What I would have expected would be some API where I can register all these connections (outgoing connections, listening sockets, etc) and then have only one thread blocking in only one call that will watch all these objects at once, but I can't find any explanation how this is supposed to be done with lNet.

Reply by email

Bernd Kreuss
to Bernd
Bernd wrote 5 lines
What I would have expected would be some API where I can register all these connections (outgoing connections, listening sockets, etc) and then have only one thread blocking in only one call that will watch all these objects at once, but I can't find any explanation how this is supposed to be done with lNet.

I can now answer my own question:

It seems it is meant to be used in the following way. The first thing I have to do is to have my own instance of a TLEventer class:

  FEventer: TLEventer;

and instantiate it:

  FEventer := BestEventerClass.Create;

and then set a short timeout (1000ms or so) to make the eventer blocking but still be able to check the termination of the thread in regular intervals and create a thread that calls CallAction in an infinite loop:

  procedure TEventerThread.Execute;
  begin
    FEventer.TimeOut := 1000;
    repeat
      FEventer.CallAction;
    until Terminated;
  end;

And then I can create as many TLTcp instances as I need and for every such TLTcp the first thing after creation is to set the Eventer property:

  FLnetListener := TLTcp.Create(self);
  with FLnetListener do begin
    Eventer := FEventer;
    OnAccept := @OnListenerAccept;
    FLnetListener.Listen(FListenPort);
  end;

and even more such objects for outgoing connections (one for each connection), each setting the Eventer to the same one and only eventer instance:

constructor TBuddy.Create(AClient: IClient);
  inherited Create;
  FClient := AClient;
  FLnetClient := TLTcp.Create(nil);
  FLNetClient.Eventer := AClient.Eventer;
  ...
end;
procedure TBuddy.InitiateConnect;
begin
  with FLnetClient do begin
    OnConnect := @Self.OnProxyConnect;
    OnReceive := @Self.OnProxyReceive;
    OnDisconnect := @Self.OnProxyDisconect;
    OnError := @Self.OnProxyError;
  end;
  FLnetClient.Connect(FClient.TorHost, FClient.TorPort);
end;

Seems to work quite well, I only have to find out how to properly shut down incoming connections that were disconnected by the other side and then start rapidly firing recv events with 0 bytes (CPU goes 100%), the only way seems to be to set the Dispose property of the TLHandle to true once I receive 0 bytes for the first time on this connection and then pretend the connection is closed but I am not sure if this is allowed and I am not leaking OS handles that way. Also with my code I seem to be able to produce strange crashes inside heaptrc that I have never seen before, still investigating how to reproduce.

Bernd

Reply by email

Bernd
to Bernd Kreuss

2012/5/29 Bernd Kreuss :

Also with my code I seem to be able to produce strange crashes inside heaptrc that I have never seen before.

Here it is again:

Marked memory at $ACBCEC60 invalid
Wrong signature $AAAAAAAA instead of F1283A25
$015D75BD FINISH_HEAP_FREE_TODO_LIST, line 425 of ../inc/heaptrc.pp $015D75F0 TRY_FINISH_HEAP_FREE_TODO_LIST, line 434 of ../inc/heaptrc.pp $015CCAB2 GETMEM, line 251 of /home/bernd/lazsvn/fixes_2_6/rtl/inc/heap.inc $0164E362 TTEMPLIST__GETENUMERATOR, line 127 of
/home/bernd/proj/git_torchat_laz/src/client/tc_templist.pas $0164DE59 TTEMPLIST__CHECKSTATE, line 82 of
/home/bernd/proj/git_torchat_laz/src/client/tc_templist.pas $0161535A TTORCHATCLIENT__PUMP, line 220 of
/home/bernd/proj/git_torchat_laz/src/client/tc_client.pas $015B7FEE CB_PURPLE_TIMER, line 136 of purpletorchat.lpr $00AE992F
Marked memory at $ACBCEC60 invalid
Wrong signature $AAAAAAAA instead of F1283A25
$015D75BD
$015D8B6A
$015D75BD
$015D75F0
$015CCAB2
$0164E362
$0164DE59
$0161535A
$015B7FEE

and then it is frozen.

Reply by email

Jonas Maebe
to Bernd
Bernd wrote 6 lines
2012/5/29 Bernd Kreuss : > Also with my code I > seem to be able to produce strange crashes inside heaptrc that I have > never seen before. Here it is again:

It means that you have memory corruption in your program (using objects after freeing them, writing via pointers that have already been freed, writing past end of a memory block allocated to a pointer, etc).

Jonas

Reply by email

Bernd
to Jonas Maebe

2012/5/29 Jonas Maebe :

It means that you have memory corruption in your program (using objects after freeing them, writing via pointers that have already been freed, writing past end of a memory block allocated to a pointer, etc).

This seems to happen inside the TLEpollEventer (it won't happen when using the TLSelectEventer), strange things happen sometimes when the other side (a socks server) sends its reply (8 bytes) and then immediately disconnects. On the next iteration of the event loop it will either correctly fire the OnDisconnect event and everything is ok or (sometimes) it will immediately call OnReceive again a million times with 0 bytes (this gives me 100% CPU).

No matter what I try when receiving the socks4 error message (either just do nothing in OnReveive() and hope the disconnect event will fire on its own in the next iteration (it will almost always) or trying to fpshutdown() to always enforce this event or fpshutdown() and also setting Dispose:=true (so it won't be polled again at all) or simply calling the Disconnect() method, no matter what I do it will sometimes enter a very strange corrupted state in the next iteration of CallAction(). Unfortunately I don't know enough about ePoll to know how to debug this but I doubt ePoll itself is buggy, there must be something flawed in the way lNet's is using it.

Reply by email