Author Topic: Steve's Open Server  (Read 4246 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Steve's Open Server
« on: November 25, 2019, 04:38:11 pm »
Since I've finally gotten QB64 up and going for myself with TCP/IP connecting across the internet, I thought I'd go ahead and use it to create a semi-permanent server which could be used as a means to facilitate online games, high score lists, chat sessions, and other such things...

The concept here is rather simple:

1) I host a server and try and keep it up and running 24/7 on an old PC in my basement.  Warning, it might be laggy and slow, but it works.  It's a PITA to use Anti-Virus Protection and Firewalls with open ports, so I prefer if the PC which I'm going to use for this experiment remains independent from the rest of my network, contains no useful information, and is just a bare bones box which I don't have to worry about hackers destroying on me.  This server is going to be old, slow, and patience might be needed when accessing it -- but it'll be 100% FREE!!  (Unless you guys run up tons of bandwidth usage with it, in which case I might ask for donations to help keep it up and going...)

2)This server will be available for the public to make use of.  If you have a game which you want to use with online communications, you're welcome to connect through this server.  I'll explain the process behind it, as development goes along.

At the moment, the steps look like the following, but they're open for any and all changes as development occurs:

  • You have to connect to the server.
  • You user will need to [REGISTER] their chosen name and password.  (Names are unique, with only one account allowed for all Steve Server services.)
  • Users will need to [LOG IN] to send/receive data using the server.
  • Your program will need to respond to [PING][PONG] requests if you plan to stay connected for more than a minute.
  • Data needs to be sent to the server following the proper format to be read.  This basically consists of "[COMMAND]text", so something like "[REGISTER]SMcNeill,password" would be the command for a new user to register and store a password.

For games, commands would look like:

"[SET GAME]My Game's Name" -- this would set the game which you want to talk to the server about.  Only one game can be set at a time, without erroring out.
"[CREATE GAME]User Name #1, User Name #2" -- this would create a game between user1 and user2, and save their moves/chat/history in it's own file on the server's drive.
"[JOIN GAME]User Name #1, User Name #2 -- this is going to allow people to rejoin old games in progress.
"[CHAT GAME]..."  -- command to send chat back and forth between the players in the games.
"[CLOSE GAME]...."  -- this will close the game and mark it from ACTIVE to FINISHED.

Programs should be able to send and receive basic text, following the sample syntax above to communicate and share information across the server.  Large Massively-Multiplayer Games aren't going to be usable (at least not initially) with this concept, but games between limited opponents will be.  For now, I'm building it for 2 players, but it should be easy enough to expand to "[CREATE GAME]Player1, Player2, Player3, Player4, Player5, Player6" if necessary, in the future.

A demo of what the bare minimum a client should have (so far) is about this much:

Code: QB64: [Select]
  1. 'Messages which we transfer of importance.
  2. '[Connection Successful]
  3. '[OK]
  4. '[ERROR]
  5.  
  6.  
  7. CONST DefaultPort$ = "7200"
  8. CONST DefaultIP$ = ""
  9. CONST True = -1, False = 0
  10. CONST Verbose = True
  11. _DEFINE A-Z AS _INTEGER64  'we're going to send/recieve int64s usually (8 bytes).  Deal with it.
  12. DIM SHARED Host, Client, LastSeen
  13.  
  14.  
  15. SCREEN _NEWIMAGE(800, 600, 32)
  16.  
  17. Client = ConnectAsClient(DefaultPort, "localhost")
  18. PRINT "Ready"
  19.  
  20.     k = _KEYHIT
  21.     IF k > 0 THEN
  22.         _KEYCLEAR
  23.         PRINT "Type junk =>";
  24.         LINE INPUT junk$
  25.         Send Client, junk$, False
  26.         PRINT junk$
  27.         _KEYCLEAR
  28.     END IF
  29.     Receive Client, what$
  30.     IF what$ <> "" THEN PRINT what$: what$ = ""
  31.     _LIMIT 30
  32.  
  33. FUNCTION ConnectAsClient (Port$, IP$)
  34.     IF Verbose THEN PRINT "Connecting to Host as Client";
  35.     DO
  36.         count = count + 1
  37.         temp = _OPENCLIENT("TCP/IP:" + Port$ + ":" + IP$) 'attempt to join as client
  38.         _LIMIT 10
  39.         IF Verbose THEN PRINT ".";
  40.     LOOP UNTIL temp <> 0 OR count > 100
  41.     IF Verbose THEN PRINT
  42.     IF count > 50 THEN
  43.         IF Verbose THEN PRINT "Cannot connect to Host.  Terminating program."
  44.         END
  45.     END IF
  46.     IF Verbose THEN PRINT "Client Connected Successfully."
  47.     ConnectAsClient = temp
  48.  
  49.  
  50. SUB Send (Who, What$, GetConfirmation)
  51.     IF What$ = "" OR Who = 0 THEN EXIT SUB
  52.     DO
  53.         attempt = attempt + 1
  54.         l = LEN(What$)
  55.         IF GetConfirmation = False THEN l = -l
  56.         PUT #Who, , l 'send the length
  57.         PUT #Who, , What$ 'send the data
  58.         IF GetConfirmation THEN
  59.             l = CheckSum(What$) 'send a checksum to make certain the data we sent was recieved properly
  60.             PUT #Who, , l
  61.             DO
  62.                 count = count + 1
  63.                 GET #Who, , a$
  64.                 IF a$ <> "" THEN result$ = result$ + a$
  65.                 _LIMIT 10
  66.                 IF count > 50 THEN result$ = "[ERROR]"
  67.             LOOP UNTIL result$ = "[OK]" OR result$ = "[ERROR]" OR LEN(result$) > 7
  68.             IF result$ = "[OK]" THEN EXIT SUB
  69.             IF Verbose THEN PRINT "Error sending data.  Trying again ("; attempt; " of 5)."
  70.         ELSE
  71.             EXIT SUB
  72.         END IF
  73.     LOOP UNTIL attempt > 5
  74.     IF Verbose THEN PRINT "Cannot Send Data.  Terminating connection.]"
  75.     END
  76.  
  77. SUB Receive (Who, What$)
  78.     IF Who = 0 THEN EXIT SUB
  79.     GET #Who, , l
  80.     IF l <> 0 THEN
  81.         DO
  82.             GET #Who, , a$
  83.             IF a$ <> "" THEN What$ = What$ + a$
  84.             _LIMIT 10
  85.         LOOP UNTIL LEN(What$) >= ABS(l)
  86.         IF l > 0 THEN 'the sender wants confirmation that the data received matches what we sent.
  87.             count = 0
  88.             DO UNTIL LEN(What$) >= l + 8 OR count > 30
  89.                 count = count + 1
  90.                 GET #Who, , a$
  91.                 IF a$ <> "" THEN What$ = What$ + a$
  92.                 _LIMIT 10
  93.             LOOP
  94.             IF count > 30 THEN 'If we can't get the last 4 bytes in 3 seconds, we probably screwed up somewhere.
  95.                 'Send a failure notice back to the user.  We can't verify the data without a checksum, and that's
  96.                 'what the last 4 bytes should be.
  97.                 Send Who, "[ERROR]", False
  98.                 What$ = "" 'don't return any value for what$.  It wasn't properly received.
  99.                 EXIT SUB
  100.             END IF
  101.             'at this point, we should have the data and the 4 digit checksum.
  102.             c = CVL(RIGHT$(What$, 8))
  103.             What$ = LEFT$(What$, LEN(What$) - 8)
  104.             IF c = CheckSum(What$) THEN 'we can confirm it.
  105.                 Send Who, "[OK]", False 'let them know we got the proper data
  106.             ELSE
  107.                 Send Who, "[ERROR]", False 'let them know we got the proper data
  108.                 What$ = ""
  109.             END IF
  110.         END IF
  111.     END IF
  112.     'And if we've fallen through all the possible IF conditions, we're done!
  113.  
  114.  
  115. FUNCTION CheckSum (What$)
  116.     FOR i = 1 TO LEN(What$)
  117.         CheckSum = CheckSum + ASC(What$, i)
  118.     NEXT
  119.  

The first working games which I plan to add to this service will be Checkers and then Chess.  The plan isn't to require the players to be active 24/7, but to be able to play at their own pace.  Player one makes a move, types a little text to start a conversation with, the server stores that information.  Player two logs in, sees that information, they can make their move, respond to the chatting, then log out... Rinse and repeat until the game is won. 

If both players can only log in once every few hours, a game of Chess/Checkers might take several days to complete.  If both are logged in at the same time, then they could almost play in "real time" against each other. 

The idea is in its infancy, with a lot of work left to go before it'll be up and running completely. There's a lot more work required on the host side than it is on the client side, as the host has to read and parse commands, decipher what to do with them, store and retrieve data from files which it's saving on the hard drive, and then send it all back to the initial user  (or toss error messages to them, in case of failure along the way), but I'm getting there with it.

At this point, the server is up and running (when I click it on to test it), and I can register and log in and out test accounts.  Text can be shared publicly, as per a chat program, and -- when necessary -- data can be verified when sent back and forth between the host and clients (such as when I might want to do a file transfer across the net).

I just need to finalize my game communication protocol/syntax, and teach it how to respond to various different requests, and a prototype version of the server will be available for the public to connect to and play with...

I simply thought I'd mention the concept a little early, in case anybody else out there might be interested in making use of it's services.   Storing things like highscore lists and retrieving them should be simple as heck ("create game, join game, send list, receive list, leave game" type commands are all that would need to be implemented), and once those simple lists are working, storing information of games between two (or more) players shouldn't be very far behind...

So, if you're interested guys, feel free to start working on your own games anytime you want.  Just remember, players would need to:
1) Register
2) Log In
3) Create or Join a Game
4) Send properly formatted text
5) Be able to parse the properly formatted responses.





https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Steve's Open Server
« Reply #1 on: November 26, 2019, 10:38:47 am »
1) I host a server and try and keep it up and running 24/7 on an old PC in my basement.  Warning, it might be laggy and slow, but it works.  It's a PITA to use Anti-Virus Protection and Firewalls with open ports, so I prefer if the PC which I'm going to use for this experiment remains independent from the rest of my network, contains no useful information, and is just a bare bones box which I don't have to worry about hackers destroying on me.  This server is going to be old, slow, and patience might be needed when accessing it -- but it'll be 100% FREE!!  (Unless you guys run up tons of bandwidth usage with it, in which case I might ask for donations to help keep it up and going...)

The epitome of using an 'open' server. nothing important what so ever to be stolen,molested, or destroyed!

If you have the time Steve, take a peek at my Archery game and see if that might be a candidate for storing a simple and basic High Score list on the server for?
https://www.qb64.org/forum/index.php?topic=1627.0
Granted after becoming radioactive I only have a half-life!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Steve's Open Server
« Reply #2 on: November 30, 2019, 08:55:13 am »
Heya Steve,

Was wondering if the server is open to public testing yet, i.e., can I use my Sprezzo client to PING/PONG your server?

I know you'd have to hard-code that response in, but alongside (or before) all the game-related commands, would it be worth deciding on a dead-simple set of very basic commands? Ping for one example, but also things like Time, or UpTime, or a special response to the word Help, or anything like that.

Reason I ask is I just got hold of a regular internet connection so I can now join in the server/client/chatbot race. That, and I'm completely nuking the Sprezzo code and replacing it with something better. Looking to test certain parts outside of my LAN.
« Last Edit: November 30, 2019, 08:56:22 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Steve's Open Server
« Reply #3 on: November 30, 2019, 09:32:49 am »
It’s now up and sending/receiving files.  (Though not in the most secure manner yet.)

I haven’t assembled all the pieces into one pre-gathered package yet, so folks can just ‘$INCLUDE the parts as a library, as I’m working to streamline the process and give it several nice, functional GUI tools to interface with, but the process is this one:

Client connects to server.
User registers or logs in. 
At this point you can [GAME SET] which will basically reserve a directory on the server to store your files.
Then you [GAME GET] a file to retrieve your data.
[GAME PUT] sends a file so the server will save it in your directory.

So:  [LOGIN]STxATxIC
[GAME SET]Sprezzo
[GAME GET]anyfile.anyext
[GAME PUT]anyfile.anyext

Over time, I’ll add more functionality to it, but for now, it’s doing the most important work already — receiving, saving, restoring, and sending files.

Look at the two posts in Samples:  Click It highlights the process fairly linearly.  And the LOG IN/ERROR BOX topic showcases the simplification and GUI process at work.  Between the two of them, you can probably get a good idea of how things are currently working. 

I wouldn’t store my bank records on it, as anyone can [GAME SET] to any directory and get and put files there (no password protection offered on those yet), but it’s a project less than a week old, or so, and interrupted by the holidays...  It still needs a lot of work, but I’m happy for what it *is* doing at the moment.  ;D

Give me time, and be certain to offer feedback and user requests.  Eventually, it might grow into something we can all feel secure making use of, here in the QB64 community.

Log In screen: https://www.qb64.org/forum/index.php?topic=1931.0
Click It: https://www.qb64.org/forum/index.php?topic=1924.0
« Last Edit: November 30, 2019, 09:34:39 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Steve's Open Server
« Reply #4 on: November 30, 2019, 10:01:11 am »
Okay... thanks for those links, it was the IP address and port that I needed.

To restate my mission more succinctly, I'm looking at your registration protocols and am going to do them from my own client by hand just for fun, gaming aspect be damned. It's the politest way to hack someone's server in 2019, I guess.
You're not done when it works, you're done when it's right.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Steve's Open Server
« Reply #5 on: November 30, 2019, 10:22:25 am »
Ok, so I just sent the text

[REGISTER]STxAxTIC,cheese

to the server, which was headed by the port and IP address I use for local testing so I expect no response, of course, but it DID tell me that the text sent over. Cool.

The question now is, how does your program want me to include my return port and address to receive the [OK] response? The default I use is:

port:address:message

To be exact:

Code: QB64: [Select]
  1.                    
  2. UserInput = ReturnPort + ":" + ReturnAddress + ":" + UserInput
  3. HostHandle = _OPENCLIENT("TCP/IP:" + PortOut + ":" + AddressOut)
  4. IF (HostHandle = 0) THEN
  5.     PRINT "Unable to connect."
  6.     PRINT
  7.     CALL SendLive(HostHandle, "", UserInput, "", 128, .05)
  8.     CLOSE HostHandle
  9.     PRINT "Sent input."
  10.     PRINT
  11.  

See what I'm asking?
You're not done when it works, you're done when it's right.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Steve's Open Server
« Reply #6 on: November 30, 2019, 10:26:50 am »
Okay... thanks for those links, it was the IP address and port that I needed.

To restate my mission more succinctly, I'm looking at your registration protocols and am going to do them from my own client by hand just for fun, gaming aspect be damned. It's the politest way to hack someone's server in 2019, I guess.

What you’re interested in is the Send, Receive, Verify routines in Click It.  The server ignores anything that doesn’t fit a certain format, and it always sends a reply to anything you send it, so always check/clear that. 

CHR$(2) tells it, “data incoming”, followed by an INTEGER64 telling it the byte size of what to expect, then followed by the data.   

Commands are always the first thing it looks for, and they’re enclosed in braces [COMMAND] followed by necessary details.  For example:

Code: [Select]
[GAME SET]Foo
The above will create a directory on the server called “Foo”, if it needs to, and then it’ll use it for your future requests, such as “[GAME PUT]filename” + CHR$(0) + Data$, which will store your Data$ in file$ on the server, in that directory you set previously.[/code]
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Steve's Open Server
« Reply #7 on: November 30, 2019, 10:31:28 am »
Ah alrighty - That clears things up for how to prepare the data, so to speak - and did you see what I meant about the return Port:Address question?

Because in my experience, when you extract that info from _CONNECTIONADDRESS, the port is more or less random. I've found it best to just include it in the text of the message...
You're not done when it works, you're done when it's right.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Steve's Open Server
« Reply #8 on: November 30, 2019, 11:34:23 am »
Steve's sever is open? Well zip it up! No one wants to see thaaaaat!!!

Pete :D
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/