Creating a Login Server (C++)

Started by
9 comments, last by Kitt3n 15 years, 6 months ago
So, where should I start? I'm using C++, establishing network connections via winsock. I can do TCP/UDP sockets fine, but I've never used SQL, and want to see if anyone can show me a snippet on how to establish a connection to a server, and show me how to verify username / passwd information on it, within a C++ application. Thanks. Any idea would greatly be appreciated.
[size="2"][size="1"][size="2"]- Quinn
[size="2"][size="1"][size="2"]Software Developer, Mintrus
Advertisement
Can you give some more information on what the project is for? The more info we have the more tailored responses to that problem domain can be given.

My suggestion would be to start out simple. Let's say you are using tcp, you have to have a packet format to mold the stream around. A typical format might be:
struct PacketFormatHeader{   unsigned short size; // How many bytes are in the data   unsigned short opcode; // The operation code of this packet};

To which the packets data comes afterward in the stream. Given that format, let's say you define the following protocol:

Opcode: 1
Direction: Server to Client
Description: Sent when a client connects to the server, client knows it can send their username and password.
Format: None, header only packet.

Opcode: 2
Direction: Client to Server
Description: The login packet sent to the server after Opcode 1 has been received.
Format:
2 bytes login name legnth
X bytes login name
2 bytes login pass legnth
X bytes login pass

Opcode: 3
Direction: Server to Client
Description: The login response packet that signals successful login or failure.
Format:
1 byte result (0 failure, 1 success)
1 byte failure mode (only if result is 0), such as bad pass, invalid name, banned, etc..

And there, you have a simple login process setup. This of course is not secure, so once something trivial like this is working, you would add in some security measures for the login credentials. You could MD5 the password and send that along instead (would need to update the packet format of course), encrypt the entire packets (would need to send a key to the client on connection, possibly in opcode 1), and the list can go on.

You will definitely want to implement some smart packet handling code, i.e. set a limit on how much data a client can send you in any packet. That way, if anyone tries to crash your server with bad allocations or a huge allocation, they will fail. You also need to make sure the server won't crash if packet data is not in the same format it should be, there is a lot of account for and design around!

The actual implementation of all that just depends on your networking code. If you have your own client / server setup, you can get started with designing a protocol and play around with it. If you have no network code that is generic enough to use as a base, your first goal is to get one either by 3rd party or DIY.

I chose the DIY method and have learned a lot from it. TCP is by no means easy or simple to implement. You can come up with something that "works" fairly fast, however, if you are doing any serious development, you need something that "works correctly". If you want to read about some of my networking experience I have some in my journal, and much more to come in that regards.
Quote:Original post by QuinnJohns
and want to see if anyone can show me a snippet on how to establish a connection to a server, and show me how to verify username / passwd information on it,


Using the popular MySQL, the C API is a good start with regards to actual code.

Define a table that contains username string, password hash and session token.

When client connects, it send username and password hash. You use that to query the database (SELECT passwordhash FROM accounts WHERE username = ...). Using client's IP and port and perhaps some other information, generate session token. Store token into database and send it to client. (UPDATE token = ... WHERE username=...). Other representation are possible, tokens can be stored in separate table and associated with username. Or they can be files on disk.

From here on, when client wishes to do some real work, it only sends the token, which you compare to one in database.

If client is inactive for X minutes, purge its token from the database.
Storing the session token in the database is not very high performance, especially since it's ephemereal. You'd be better off just storing it (keyed by user and IP, say) in a hash table on the server itself.

However, just using a random ID isn't very secure. You're probably better off using a cryptographic cookie with some more data in it. Check the Forum FAQ for some links regarding that ("authentication for games" and others).

Some other things to keep in mind:
- The default MySQL API isn't asynchronous. You'll probably want to do something about that, such as running the entire API in a second thread (you can't split it up over multiple threads, though).
- You never want the clients connecting to the database. In fact, you want the db server to be firewalled off, so the only machine(s) that can get to it is/are the front-end servers.
enum Bool { True, False, FileNotFound };
@Drew_Benton: I'm going to be working on improving my knowledge, so I can use this on any facet of network programming, from MMOG, to anything else that may require any sort of login/authentication.

I'm fairly proficient with Winsock & Directplay, I've utilized TCP / UDP for several projects, in regards to games, chat clients, ftp clients - and what not. I just dislike not knowing much about a particular topic, and always stride to want to improve what I do know.

So far the suggestions are amazing, Antheus and hplus0603, their answers are more tailored to what I was looking for information regarding. Does anyone know of any tutorials / documentation that was extremely helpful to them, regarding the topic, particularly, password hash and session tokens.

Thanks for any more information I can acquire, I'll also be taking a look at the FAQ, in the mean time.

- Quinn

[Edited by - QuinnJohns on October 2, 2008 11:40:08 PM]
[size="2"][size="1"][size="2"]- Quinn
[size="2"][size="1"][size="2"]Software Developer, Mintrus
Quote:Original post by Antheus
When client connects, it send username and password hash. You use that to query the database (SELECT passwordhash FROM accounts WHERE username = ...). Using client's IP and port and perhaps some other information, generate session token. Store token into database and send it to client. (UPDATE token = ... WHERE username=...). Other representation are possible, tokens can be stored in separate table and associated with username. Or they can be files on disk.


You wouldn't happen to have any sample code on the C++ functions, etc, necessary to query the database, would you?

Thanks.


[size="2"][size="1"][size="2"]- Quinn
[size="2"][size="1"][size="2"]Software Developer, Mintrus
Quote:Original post by QuinnJohns
You wouldn't happen to have any sample code on the C++ functions, etc, necessary to query the database, would you?


Here's a huge page of stuff on MySQL++, a C++ binding for MySQL (that is a chapter out of the user guide for the library). Go over those examples and that's pretty much what your C++ code will resemble.
After including the mysql c api in project and creating a database/table using a mysql db client (I use HeidiSQL for MySQL) I wrote a little program example, might help you:

(Excuse my personal indention)

 #include <winsock.h>#include <iostream>#include <mysql.h>#include <string>using namespace std;string query;string acctname;string acctpass;string email;int main () {		cout << "Initializing MySQL...\n";		MYSQL mysql; 	//Initiatilize	if (mysql_init(&mysql)) {		cout << "Initialize successful!\n";	}		else {		cout << "Initialize failed!\n";		return 0;	}	//Connect		cout << "\nConnecting to database...\n";	if (mysql_real_connect(&mysql,"127.0.0.1","root","passhere","dbname",0,0,0)) {		cout << "Connected to database.\n";	}	else {		cout << "Connection failed!\n";                return 0;	}		query = "INSERT INTO accounts (acctname,acctpass,email) VALUES ('";		cout <<"\nAccount Name:\n";		cin >> acctname;		cout << "\nAccount Password:\n";		cin >> acctpass;		cout << "\nEmail:\n";		cin >> email;		query.append(acctname);		query.append("','");		query.append(acctpass);		query.append("','");		query.append(email);		query.append("')");		cout << "\n[SQL CODE] - \" " << query << " \" \n";		mysql_query(&mysql,query.c_str());while (true) {}}


The .appends look a bit messy but what it prints out would be something like:

INSERT INTO accounts (acctname,acctpass,email) VALUES ('Leaedas','mypasswordsucks','Leaedas@hotmail.com')

[Edited by - Leaedas on October 4, 2008 12:36:03 AM]
Can I jump in here and ask, why are you using C++ to do this job? Why not use C# for example?

If you were using C#, you probably wouldn't even have had to ask this question here. In C# its one single line of code to query a database!!!!
FTA, my 2D futuristic action MMORPG
Quote:Original post by graveyard filla
Can I jump in here and ask, why are you using C++ to do this job? Why not use C# for example?

If you were using C#, you probably wouldn't even have had to ask this question here. In C# its one single line of code to query a database!!!!


While that is true, it would not really answer the underlying problem. Namely, the following "diagreement":
Quote:Storing the session token in the database is not very high performance, especially since it's ephemereal. You'd be better off just storing it (keyed by user and IP, say) in a hash table on the server itself.
vs.
Quote:Define a table that contains username string, password hash and session token.


Lacking the scope of question, or actual requirements, either answer is correct. One is fast, easy and good enough, the other goes deeper into additional issues, such as:
- The default MySQL API isn't asynchronous. You'll probably want to do something about that, such as running the entire API in a second thread (you can't split it up over multiple threads, though)./quote]

And given that it's often hard to judge someone's background, finding appropriate answer isn't always possible from the start.

On same note: why write your own software, why not just outsource it somewhere? Or license third-party solution. Or order the million monkeys in the backroom to start typing.

As far as original question goes - it was about how login server interacts with database. While it's possible to do it in a few lines, or better yet, use third-party library that does it - it doesn't really answer the question.


If someone were to ask a different question, perhaps something like:
Quote:I'm developing an online poker game, played over web, with AJAX updates, 4 players + dealer, ............., login server, ........., mastercard authorization, ...... Oracle database ..... $25,000 budget, .... and so on....
Then a different question might be more appropriate, one that includes references to existing projects, or perhaps companies/vendors/authors providing applicable solutions.

This topic is closed to new replies.

Advertisement