TurboMagic 92 Posted October 13, 2020 Hello, in my project I ue ICS V8.62 in Delphi 10.3.3 to detect some devices on the network per UDP. Sometimes my routine works as expected and sometimes it crashes. When it crashes it happens on a call to Socket.MessagePump and inside that one on the call to Application.ProcessMessages. My code is inside an Button click handler and it immediately crashes when pressing F7 in the debugger on Application.ProcessMessages. Since it's a VCL app unit forms is used. Application is assigned. My socket is a plain TWSocket, Proto is 'UDP' and local IP is set to one of the interfaces the computer has to search on that one and LocalPort is 0. I call Socket.Connect and then immediately Socket.MessagePump where it crashes in. Anybody any clue? Share this post Link to post
Angus Robertson 574 Posted October 13, 2020 If you are connecting to another device, you don't need to set a local IP address, use 0.0.0.0 and let Windows worry about it. Sometimes interfaces come and go, that could cause an error. Local address is really for listening sockets, although can be used on servers with multiple IP addresses to select an outgoing address. Angus Share this post Link to post
TurboMagic 92 Posted October 13, 2020 I do set the interface because it is a broadcast to 255.255.255.255 and I want it to go out to all interfaces. But: would that be really connected to the MessagePump crash in Application.ProcessMessages? Share this post Link to post
Angus Robertson 574 Posted October 13, 2020 I have never seen a message pump crash with ICS. But I know using a non-existent interface will fail. Been a long time since I did a project with UDP broadcasts. Angus Share this post Link to post
Fr0sT.Brutal 900 Posted October 13, 2020 Why do you need Socket.MessagePump at all? Share this post Link to post
TurboMagic 92 Posted October 13, 2020 (edited) In order to obtain the list of interfaces I loop through I use IcsGetInterfaceList. This returns 3 interfaces to me: 127.0.0.1 (loopback), which I skip, 10.149.x.y (x and y have valid numbers) which is the IP of that VM I'm running in and the last one is 0.0.0.0. This is my code: Socket := TWSocket.Create(nil); Socket.Proto := 'UDP'; Socket.Addr := '255.255.255.255'; Socket.Port := '1234'; Socket.LineMode := false; Socket.OnDataAvailable := OnUDPDataAvailable; Addr.S_addr := IfList[i]^.iiAddress.AddressIn.sin_addr.S_addr; Socket.LocalAddr := string(WSocket_inet_ntoa(Addr)); Socket.LocalPort := '0'; Socket.Connect; Socket.MessagePump; Socket.SendLine('Hallo?'); OnUDPDataAvailable is declared as method like this: procedure TMyClass.OnUDPDataAvailable(Sender: TObject; ErrCode: Word); Edited October 13, 2020 by TurboMagic Share this post Link to post
TurboMagic 92 Posted October 13, 2020 11 minutes ago, Fr0sT.Brutal said: Why do you need Socket.MessagePump at all? I know that it would be better to not use it. It often works, but just not always. In my case the routine running this shall already return the list of the search so after the code fragment shown in my post above, which is in a loop going through all interfaces determined as plausible ones, I have a waiting loop so received answers which are noted in some list have time to arrive. It's just to find out if a device answers to this request so it is present and to get it's IP. Share this post Link to post
Angus Robertson 574 Posted October 13, 2020 Using a redundant MessagePump without threads is untested and certainly serves no purpose before making any requests or listening. If you remove it, does the code work? The LocalIPList function is an easier way to get a list of addresses as strings, you need to set family and IPPROTO_UDP protocol, the default is TCP only. Angus Share this post Link to post
Fr0sT.Brutal 900 Posted October 13, 2020 (edited) 58 minutes ago, TurboMagic said: I know that it would be better to not use it. It often works, but just not always. From the code above I see you just trying to use async event-driven classes in sync mode. While this approach appears in several places in ICS itself, it's not a recommended way of using. You must understand the consequences. The simplest example is: if you launch this code from button click, MessagePump will retrieve and dispatch all Windows messages so the button will be unpushed and user will be able to push it again. P.S. In fact, I never used this function so I could be wrong here. I'm surprised to see it in ICS methods besides TCustomSyncWSocket.WaitUntilReady. Edited October 13, 2020 by Fr0sT.Brutal Share this post Link to post
FPiette 383 Posted October 13, 2020 1 hour ago, TurboMagic said: Socket.Connect; Socket.MessagePump; Socket.SendLine('Hallo?'); Don't do that. Use OnSessionConnected event and write a handler which checks if connection is successful and if it is, can SendLine to send something. Share this post Link to post
TurboMagic 92 Posted October 13, 2020 (edited) Is there really such an OnSessionConnected event on a connection less UDP socket? Remember: I'm using UDP here. Edited October 13, 2020 by TurboMagic Share this post Link to post
FPiette 383 Posted October 13, 2020 9 minutes ago, TurboMagic said: Is there really such an OnSessionConnected event on a connection less UDP socket? Yes, there is so that the use of TWSocket is the same for both TCP and TCP. Look at the source code if you are interested. Share this post Link to post
Angus Robertson 574 Posted October 13, 2020 Yes, OnSessionConnected event is fired for UDP, but should be virtually instantaneous since no traffic is sent, you should have waited until the state changed before sending anything, but send would just fail and you are ignoring errors and it would not explain the exception. Angus Share this post Link to post
TurboMagic 92 Posted October 13, 2020 Ok, now I better understand. Have to find the time to properly refactor this code. Thanks so far. Share this post Link to post