Network fog is thickening.....

Everything else that doesn't fall into one of the other PB categories.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by NShade.

I just started work on some netcode and all was going ok (fairly) till i got Num3 to compile me the test code into an exe. Then s... hit the fan...

If run both the server code and the client test codefrom inside PB, all goes as planed.
If i run the server from PB and the compiled client test exe, all is fine also. BUT, if i comment out the last line of the client test, it doesnt. Data doesnt get sent.

I dunno this is a PB thing, windows thing or if it only happens on a local machine (ie no delay in comms), but its weird that the disconnect msg arrives at server before the data taht was sent, when the data was actually sent before the app quit.....

Any comments on this? Oh, and here is teh code... Its a bit sloppy, but works :P

-----------
server code
-----------

Procedure conout(tstring$)
Shared opcon
If opcon
PrintN(tstring$)
EndIf
EndProcedure

;Open a console so we can track server progress..... no console, no tracking
opcon=OpenConsole()

initnet=InitNetwork()
If initnet=0
mresult=MessageRequester("Warning","Sorry, no network, shutting down!",#PB_MessageRequester_Ok)
End
EndIf

opennetserver=CreateNetworkServer(9999)
If opennetserver=0
mresult=MessageRequester("Warning","Sorry, couldnt start server!",#PB_MessageRequester_Ok)
End
EndIf

If opcon
PrintN("Ok, server started!")
EndIf

;
;
;

maxclients=250
connectedclients=0
authedclients=0

Structure clientconn
cid.l
cauth.b
cuname$
cpassw$
csig1.b[32]
csig2.b[32]
EndStructure

NewList cconns.clientconn()

Dim buffermem.b(512) ; maxpacket size anyway

Procedure NewCon()
Shared connectedclients, maxclients
conout("NewCon()")
ncid=NetworkClientID()
;Oh boy, another one fell 4 it..... evil grin....
conout("Got a live one here!")
connectedclients+1
;Did we go over limit?
If connectedclients>maxclients
;Damn, we did. Lest scan and see if we can find/kick unauthed clients
;We couldnt, so, drop this one... sorry dude
CloseNetworkConnection(ncid)
connectedclients-1
conout("Droped conn... too many already")
Else
;Were still ok.... lets add this one
AddElement(cconns.clientconn())
cconns.clientconn()\cid=ncid
;Lets hope he auths
EndIf
EndProcedure

Procedure ReceiveDataFromNetwork()
Shared connectedclients
conout("ReceiveDataFromNetwork()")
ncid=NetworkClientID()
conout("data from "+Str(ncid))
;Find who wants our attention. Try last user 1st, may be him again
If ncid=cconns.clientconn()\cid
;Lucky.....
Else
For c.l=1 To CountList(cconns.clientconn())
SelectElement(cconns.clientconn(),c.l)
If cconns.clientconn()\cid=ncid
toselect=c.l
EndIf
Next
;Gotcha
SelectElement(cconns.clientconn(),toselect)
EndIf
;Is it an auth?
conout("doing auth")
If cconns.clientconn()\cauth=0
;Yup, it is
authbytes= ReceiveNetworkData(ncid, @buffermem.b(0), 512)
Debug authbytes
If authbytes16
;Oh oh, hes not a real one, now is he.....KILL the conn NOW! ... and free resources :)
CloseNetworkConnection(ncid)
DeleteElement(cconns.clientconn())
connectedclients-1
conout("Kicked a faker!!! Bad uname/passw length!!!")
Else
;Ok, do the 1st auth stage
clientfname$=""
For c.l=0 To 15
clientfname$=clientfname$+chr$(buffermem.b(c.l))
Next
opfile=OpenFile(0,clientfname$+".sig")
If Lof()=0
;No such client.... drop him and cleanup
CloseNetworkConnection(ncid)
DeleteElement(cconns.clientconn())
connectedclients-1
CloseFile(0)
DeleteFile(clientfname$+".sig")
conout("Droped "+clientfname$+" No such user!")
EndIf
EndIf
Else
EndIf
EndProcedure

Procedure ClientDropped()
Shared connectedclients
conout("ClientDropped()")
ncid=NetworkClientID()
; Damn, he got away..... Find who quit. Try last user 1st, may be him again
If ncid=cconns.clientconn()\cid
;Lucky.....
Else
For c.l=1 To CountList(cconns.clientconn())
SelectElement(cconns.clientconn(),c.l)
If cconns.clientconn()\cid=ncid
tokill=c.l
EndIf
Next
EndIf
;Cleanup after him
SelectElement(cconns.clientconn(),tokill)
DeleteElement(cconns.clientconn())
connectedclients-1
conout("Another one blew town.....")
EndProcedure
;
;
;

Repeat
netevent=NetworkServerEvent()
Select netevent
Case 0
Delay(1) ; Dont busy loop, it sucks
Case 1
NewCon()
Case 2
ReceiveDataFromNetwork()
Case 4
ClientDropped()
EndSelect
Until closeserver=1
;
;
;

CloseNetworkServer()
mresult=MessageRequester("Warning","Ok, server stoped!",#PB_MessageRequester_Ok)

-----------
client code
-----------

;Open a console so we can track server progress..... no console, no tracking
opcon=OpenConsole()

initnet=InitNetwork()
If initnet=0
mresult=MessageRequester("Warning","Sorry, no network, shutting down!",#PB_MessageRequester_Ok)
End
EndIf

Procedure connsendstring(tstring$)
Shared cid
SendNetworkData(cid,@tstring$,Len(tstring$))
EndProcedure

;
; bad conn 1 bad user name
;

cid=OpenNetworkConnection("192.168.0.1",9999)

If cid
If opcon
PrintN("Ok, found server.")
EndIf
connsendstring("rheshadeshadowsn")
;by now he should have dropped me :)
Else
mresult=MessageRequester("Warning","Funny, no server found... is it running????",#PB_MessageRequester_Ok)
End
EndIf

;
; bad conn 2 uname too big
;

cid=OpenNetworkConnection("192.168.0.1",9999)

If cid
If opcon
PrintN("Ok, found server.")
EndIf
connsendstring("theshadeshadowsnn")
;by now he should have dropped me :)
Else
mresult=MessageRequester("Warning","Funny, no server found... is it running????",#PB_MessageRequester_Ok)
End
EndIf

;
; bad conn 3 uname too small
;

cid=OpenNetworkConnection("192.168.0.1",9999)

If cid
If opcon
PrintN("Ok, found server.")
EndIf
connsendstring("theshadeshadows")
;by now he should have dropped me :)
Else
mresult=MessageRequester("Warning","Funny, no server found... is it running????",#PB_MessageRequester_Ok)
End
EndIf

;
; good con
;

cid=OpenNetworkConnection("192.168.0.1",9999)

If cid
If opcon
PrintN("Ok, found server.")
EndIf
connsendstring("theshadeshadowsn")
;This time i drop myself :)
CloseNetworkConnection(cid)
Else
mresult=MessageRequester("Warning","Funny, no server found... is it running????",#PB_MessageRequester_Ok)
End
EndIf

mresult=MessageRequester("Warning","Just waiting for server to either auth or drop....",#PB_MessageRequester_Ok)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by dmoc.

Try a short delay instead of the last line. Not sure if it will help but it may be the case that variables are cleaned out too quick.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tranquil.
Originally posted by dmoc

Try a short delay instead of the last line. Not sure if it will help but it may be the case that variables are cleaned out too quick.
I posted a codesnip how to do correctly networking in the tips & tricks thread some weeks ago. Please check this.
If you want to use server/ client for a public release, you should search for security holes. (eg Buffer overflows, DOS-Attacks) this checks are not implemented in this snippets.

Anyway, a Delay(xxx) could normaly not a reliable solution for network problems. everything should work WITHOUT delays!

Mike

Tranquilizer/ Secretly!
http://www.secretly.de
Registred PureBasic User
System: Windows 2000 Server, 512 MB Ram, GeForce4200 TI 128 MB DDR, Hercules Theater 6.1 DTS Sound
System 2: Mobile Pentium 4 2.4GHz 512 MB DDR GeForce4 420-32, Windows XP Home
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tinman.
Originally posted by NShade

fine also. BUT, if i comment out the last line of the client test, it doesnt. Data doesnt get sent.
You mean this line?

Code: Select all

mresult=MessageRequester("Warning","Just waiting for server to either auth or drop....",#PB_MessageRequester_Ok)
Could it be that without the line in (bringing up the message box, causing a delay while the user clicks OK) the program ends and cleans up the network stuff before it has a chance to send it (I don't know, maybe the Windows TCP/IP stuff buffers data up to send it in a bigger packet)?


--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + all updates, PB3.51, Ed3.53)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by NShade.

Yup tin, thats it. If u make the program not quit at once, the data gets sent. If u dont, the disconnect msg overlaps the data sent msg. My guess is same as urs, Win TCP/IP stack is to blame, but im not sure....

@tranquil, thx, ill look for it. On the holes bizz, yup, i got lots of things to look for. Tough the final protocol should be pretty much bullet proof..... all it takes is a bad packet to make the server/client drop the conn .) No "man in the middle" allowed here :wink:
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by NShade.

@tranquil:

i went looking 4 the stuff, and it was an interresting read. Just one question. As u can see from the code, the 1st auth fase demands 16 bytes. Those 16 bytes would be all the data sent by a REAL client. Question is, can i be sure that a real client CAN send 16 butes? I mean, is the underlying network code handling packet loss and the like?

If i do result=SendNetworkData(cid,@tstring$,16) and result is 16, can i be sure the whole 16 bytes got there? And if its not 16, its bad, cause the client will be dropped and will need a reconnect......
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tranquil.

@NShade:

No, you cant be sure. In the first call of senddata maybe only 8 bytes are send and in the second try the rest.
In my application - as you see in the tipps and tricks thread - I use a 4 Byte header. I never believed that windows/TcpIP splits up 4 bytes through the network, but it does! You have fairly collect all your sended and received bytes and you strongly need to count them.

Mostly local host test are gone right, but the first tests via internet or in LAN failed. it was a hazle to figure that out!

Mike

Tranquilizer/ Secretly!
http://www.secretly.de
Registred PureBasic User
System: Windows 2000 Server, 512 MB Ram, GeForce4200 TI 128 MB DDR, Hercules Theater 6.1 DTS Sound
System 2: Mobile Pentium 4 2.4GHz 512 MB DDR GeForce4 420-32, Windows XP Home
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by NShade.

Then im stuck..... my app HAS to relly on the amounts of data sent/received.... I could do it, read into a buffer, and count it, but esp the auth phase MUST NOT do it..... If it does i would have to read as much data as available and then 3 choices.

1-All Data arrived
2-Too much data arrived (fake client)
3-Too few data arrived (wait for more)

1 and 2 are easy, just accept o drop conn, but 3 is bad. I now have some resources alloced waiting for the rest of auth. I have to set a waiting state var with amout of cycles it will still wait for rest b4 dropping conn. And meanwhile resources are locked to that.

This makes it vulnerable to a simples DOS session start flood. Attackers just keep init'ing sessions.... Eventually all 250 slots will be taken. And after the initial flood, u just have to keep asking for a new session every once in a while. And resources keep getting hogged.

I can prevent that by raising a temp ban on the IP, but the session start attempt will keeep coming.... It wont bring the system down, but it will crawl it to an halt.....

Just me getting wild, but IT IS somewhat like this scenario, isnt it?
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tranquil.

Its right that you might can create a list of blocked IPs but indeed you can not realy block them couse PB automatically accept_()s the connection to the socket. Thats not a real problem, you can close the socket after this again.

This is my packet protocoll:

4Bytes PacketSize, Work (thats describes the command),data, long.l for CRC (optional)

This works fine here for logons and client handlings on server.
I use structured dimensions for handling the client data. This is easyier in threads and much faster. I also use a "Slot technique". If a client connects to a server at first I check the banlist (this is a linked list couse I dont need it in threads and its easier to handle for deleting IPs out od the banlist), if client is on BanList I drop the connection asap.
If everything is allright I search for a free socket. I describe a free socket in my array if client(slot)\socket=0. Now I assign the Client, allocate his buffer and send him a short "Hello" string. Client answers again and trys to logon now, and if everything is valid and okay, server responses with "welcome". thats it.

So I dont see the problem.

I do all the networking stuff in a callback, catching his events with WSAAsyncSelect_() and that works very fine!

If you need help, just mail me to [url]mailto:tranquil@gmx.net">tranquil@gmx.net Thats better then this forum to talk about. This weekend I'm visiting my girlfriend but I will be available next monday again. :)


Cheers
Mike

Tranquilizer/ Secretly!
<a href="http://www.secretly.de[/url]
Registred PureBasic User
System: Windows 2000 Server, 512 MB Ram, GeForce4200 TI 128 MB DDR, Hercules Theater 6.1 DTS Sound
System 2: Mobile Pentium 4 2.4GHz 512 MB DDR GeForce4 420-32, Windows XP Home
Post Reply