[Done] CloseNetworkConnection()

Post bugreports for the Linux version here
swhite
Enthusiast
Enthusiast
Posts: 726
Joined: Thu May 21, 2009 6:56 pm

[Done] CloseNetworkConnection()

Post by swhite »

Hi

I notice that after using the CloseNetworkConnection() function I am unable to reopen the port unless I wait 1-2 minutes, otherwise OpenNetworkConnection() fails even if the connection is for a local port on the same PC. So I am wondering why this should be the case. Does CloseNetworkConnection() close the port gracefully so that the server knows the connection has been closed?

I am running OpenSuse 15.3 using PB 5.73.

Thanks,
Simon
Simon White
dCipher Computing
infratec
Always Here
Always Here
Posts: 6810
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: CloseNetworkConnection()

Post by infratec »

It's the same on debian stretch/buster/bullseye.

When I have to restart a PB daemon, I have to add a loop for creating the server, because it takes time until the OS allows it again.
You can check if the port is still in CLOSE_WAIT state via netstat.
Bitblazer
Enthusiast
Enthusiast
Posts: 730
Joined: Mon Apr 10, 2017 6:17 pm
Location: Germany
Contact:

Re: CloseNetworkConnection()

Post by Bitblazer »

It is likely due to socket security, check out ss (ss --tcp state CLOSE-WAIT --kill)
webpage - discord chat links -> purebasic GPT4All
infratec
Always Here
Always Here
Posts: 6810
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: CloseNetworkConnection()

Post by infratec »

I just checked it:

The used port is not listed after terminating the program (ss -tulpn).
But it is not possible to start the program again.
It needs arround 30 seconds until it's possible to create the server again.
infratec
Always Here
Always Here
Posts: 6810
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: CloseNetworkConnection()

Post by infratec »

Short code to test it:

Code: Select all

InitNetwork()

If CreateNetworkServer(0, 4444)
  
  *Buffer = AllocateMemory(1024)
  If *Buffer
    
    Repeat
      Select NetworkServerEvent()
        Case #PB_NetworkEvent_Connect
          Client = EventClient()
          SendNetworkString(Client, #CRLF$ + "Welcome! Type 'exit' to leave." + #CRLF$ + #CRLF$)
          
        Case #PB_NetworkEvent_Data
          Client = EventClient()
          Len = ReceiveNetworkData(Client, *Buffer, MemorySize(*Buffer))
          If Len
            Rcv$ = PeekS(*Buffer, Len, #PB_UTF8|#PB_ByteLength)
            Debug Rcv$
            SendNetworkString(Client, "Answer: " + Rcv$)
            If FindString(Rcv$, "exit")
              Exit = #True
            EndIf
          EndIf
          
        Case #PB_NetworkEvent_None
          Delay(5)
      EndSelect
    Until Exit
    
    FreeMemory(*Buffer)
  EndIf
  
  CloseNetworkServer(0)
EndIf
connect via

telnet 127.0.0.1 4444

after leaving via exit, it is not possible to restart the code above until some time is gone.
infratec
Always Here
Always Here
Posts: 6810
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: CloseNetworkConnection()

Post by infratec »

WIth

ss -a|grep 4444

I can see
tcp TIME-WAIT 0 0 127.0.0.1:4444 127.0.0.1:54974
infratec
Always Here
Always Here
Posts: 6810
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: CloseNetworkConnection()

Post by infratec »

I just checked that a small node server doesn't have this problem.
When I do exacly the same I can not see a TIME-WAIT socket after closing the server.

Maybe he waits in the close code to receive the FIN packets from all open connections.

And it tooks 60 seconds until I can restart the server.
That's not really acceptable for a service which needs to restart cause of an update or something similar.
infratec
Always Here
Always Here
Posts: 6810
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: CloseNetworkConnection()

Post by infratec »

Fred need to add

Code: Select all

Flag.l = 1
setsockopt_(ServerID, #SOL_SOCKET, #SO_REUSEADDR, @Flag, SizeOf(Flag))
before he bind in the CreateNetworkServer() procedure.
infratec
Always Here
Always Here
Posts: 6810
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: CloseNetworkConnection()

Post by infratec »

Found a (bug)fix:

Code: Select all

EnableExplicit


#SOL_SOCKET = 1
#SO_REUSEADDR = 2
#SO_LINGER = 13
#SO_REUSEPORT = 15


ImportC ""
  errno_location() As "__errno_location"
EndImport


Structure SO_LINGER_Structure
  l_onoff.l
  l_linger.l
EndStructure


Define Server.i, res.i, errno.l, *Buffer, Client.i, Len.i, Rcv$, Exit.i
Define SoLinger.SO_LINGER_Structure


InitNetwork()

Server = CreateNetworkServer(#PB_Any, 4444)
If Server
  
  SoLinger\l_onoff = #True
  SoLinger\l_linger = 0
  res = setsockopt_(ServerID(Server), #SOL_SOCKET, #SO_LINGER, @SoLinger, SizeOf(SO_LINGER_Structure))
  If res <> 0
    errno = PeekL(errno_location()) 
    Debug PeekS(strerror_(errno), -1, #PB_Ascii)
  EndIf
  
  *Buffer = AllocateMemory(1024)
  If *Buffer
    
    Repeat
      Select NetworkServerEvent()
        Case #PB_NetworkEvent_Connect
          Client = EventClient()
          SendNetworkString(Client, #CRLF$ + "Welcome! Type 'exit' to leave." + #CRLF$ + #CRLF$)
          
        Case #PB_NetworkEvent_Data
          Client = EventClient()
          Len = ReceiveNetworkData(Client, *Buffer, MemorySize(*Buffer))
          If Len
            Rcv$ = PeekS(*Buffer, Len, #PB_UTF8|#PB_ByteLength)
            SendNetworkString(Client, "Answer: " + Rcv$)
            If FindString(Rcv$, "exit")
              Exit = #True
            EndIf
          EndIf
          
        Case #PB_NetworkEvent_None
          Delay(5)
          
      EndSelect
    Until Exit
    
    FreeMemory(*Buffer)
  EndIf
  
  CloseNetworkServer(Server)
EndIf
Not a nice solution, but it works.

SO_REUSEADDR is the way to go, but not possible from a PB coder. It's an internal solution.
User avatar
NicTheQuick
Addict
Addict
Posts: 1218
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: CloseNetworkConnection()

Post by NicTheQuick »

+1
Should be changed and fixed.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Fred
Administrator
Administrator
Posts: 16581
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: CloseNetworkConnection()

Post by Fred »

To be investigated
stevie1401
User
User
Posts: 42
Joined: Sat Oct 18, 2014 7:14 am

Re: CloseNetworkConnection()

Post by stevie1401 »

Unfortunately, the example from infantec doesn't work for me.
That's why I always program under Linux with the Windows version under Wine. Unfortunately, the icons are no longer displayed with Wine because Fred removed them with version 5.50.
It would be nice if they were there again in case the problem cannot be solved.
User avatar
NicTheQuick
Addict
Addict
Posts: 1218
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: CloseNetworkConnection()

Post by NicTheQuick »

There's also an old post from me in the German forum: https://www.purebasic.fr/german/viewtop ... 23#p356023
So if I see this correctly, you can extract the socket number from the handle of CreateNetworkServer() and use it directly. The prerequisite is that you use #PB_Any.
I have prepared something for you. Basically, you only have to put the big CompilerIf above into your existing code and you can leave the rest as it was before.

Code: Select all

EnableExplicit

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
	#SOL_SOCKET = 1
	#SO_REUSEADDR = 2
	#SO_REUSEPORT = 15
	
	Procedure CreateNetworkServerEx(ServerID.i, Port.i, Modus, BindedIP$)
		Protected handle.i
		If ServerID.i = #PB_Any
			handle.i = CreateNetworkServer(#PB_Any, Port, Modus, BindedIP$)
			If Not handle
				ProcedureReturn handle
			EndIf
			Protected hSocket.l = PeekL(handle), enable.l = 1
			If setsockopt_(hSocket, #SOL_SOCKET, #SO_REUSEADDR, @enable, SizeOf(enable)) < 0
			   Debug "Error setting SO_REUSEADDR"
			   End
			EndIf
			If setsockopt_(hSocket, #SOL_SOCKET, #SO_REUSEPORT, @enable, SizeOf(enable)) < 0
			   Debug "Error setting SO_REUSEPORT"
			   End
			EndIf
			ProcedureReturn handle
		Else
			ProcedureReturn CreateNetworkServer(ServerID, Port, Modus, BindedIP$)
		EndIf
	EndProcedure
	Macro CreateNetworkServer(a, b, c = #PB_Network_TCP | #PB_Network_IPv4, d = "0.0.0.0")
		CreateNetworkServerEx(a, b, c, d)
	EndMacro
CompilerEndIf

InitNetwork()
Define a.i = CreateNetworkServer(#PB_Any, 8080, #PB_Network_TCP, "0.0.0.0")
I did not recheck if it still works.
Don't change the Longs into Integer. It's essential if I remember correctly.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
stevie1401
User
User
Posts: 42
Joined: Sat Oct 18, 2014 7:14 am

Re: CloseNetworkConnection()

Post by stevie1401 »

Unfortunately it doesn't work, but thank you for your efforts!
stevie1401
User
User
Posts: 42
Joined: Sat Oct 18, 2014 7:14 am

Re: CloseNetworkConnection()

Post by stevie1401 »

No change in BP 6.10 beta 4
Post Reply