Commit 280d03ee authored by Jonathan Michalon's avatar Jonathan Michalon
Browse files

Dialogue between server and bot !

Now the bot listens to answers from server.
Bot connects, then tries to login. In case the same login is already
used, it retries with another login.
parent cecc0bed
......@@ -17,24 +17,35 @@ public class Bot
uint player_suffix = 7;
OVCCClient.Game game = null;
/* connect to the server, choosing an available nickname */
/* connect to the server */
debug ("Trying to connect to server...");
server.connect_to (); /* may throw a rejection */
debug ("Connected");
/* login to the server, choosing an available nickname */
debug ("Trying to login...");
do {
/* Create our player instance */
player = new OVCC.Player ("""Clever bot %3u""".printf (player_suffix));
try {
client = new OVCCClient.Client (player);
server.connect_to (player); /* may throw a rejection */
server.login_to (player);
break;
} catch (OVCCClient.ServerError.NICKNAME_IN_USE e) {
player_suffix++;
} catch (OVCCClient.ServerError.MISSING_AUTHENTICATION e) {
server.disconnect_from ();
throw e; /* avoid infinite loop */
} catch (Error e) {
server.disconnect_from ();
throw e;
}
}
while (true);
debug ("Connected with player_suffix = %u", player_suffix);
debug ("Logged in with player_suffix = %u", player_suffix);
Thread.usleep (2*1000*1000);
/* join any open table */
debug ("Trying to join a table...");
......
......@@ -19,7 +19,7 @@
*/
/**
* Login message with login and password
* Login message with login, password and current status
*/
public class OVCC.Network.LoginMessage : StringMessage
{
......@@ -27,6 +27,18 @@ public class OVCC.Network.LoginMessage : StringMessage
public string login { get; set; default = null; }
public string password { get; set; default = null; }
public State status { get; set; default = State.QUERY; }
public enum State
{
QUERY,
OK,
ALREADY_EXISTS,
MISSING_AUTHENTICATION,
UNAUTHORIZED
}
public LoginMessage (string login, string password)
{
......@@ -38,7 +50,7 @@ public class OVCC.Network.LoginMessage : StringMessage
throws Error
{
/* FIXME separator */
message = login + "|" + password;
message = login + "|" + password + "|" + ((int)status).to_string();
return base.serialize(stream, cancel);
}
......@@ -48,11 +60,12 @@ public class OVCC.Network.LoginMessage : StringMessage
{
base.deserialize (stream, cancel);
string[] fields = message.split ("|");
if (fields == null || fields.length != 2) {
if (fields == null || fields.length != 3) {
throw new MessageError.MALFORMED_MESSAGE ("Message should have two fields");
}
login = fields[0];
password = fields[1];
status = (State)int.parse(fields[2]);
return true;
}
}
......@@ -69,6 +69,9 @@ namespace OVCC.Network
Cancellable? cancel = null)
throws Error
{
/* hack to call the class_init before using length and content of message_types */
TypeClass klass = typeof (Message).class_ref ();
Message message = null;
MessageType type;
......
......@@ -33,7 +33,7 @@ namespace OVCCClient
server = s;
try {
server.connect_to (player);
// server.connect_to (player);
} catch {}
return false;
......
......@@ -37,15 +37,20 @@ namespace OVCCClient
socket = new SocketClient ();
this.host = host;
this.port = port;
/* instance unused, just to call the class_init() */
// Message msg = new DisconnectMessage();
}
~Server ()
{
}
public /*async*/ bool connect_to (Player player)
public /*async*/ bool connect_to ()
throws ServerError
{
Message msg;
try {
SocketConnectable addr = NetworkAddress.parse (host, port);
connection = socket.connect (addr);
......@@ -55,9 +60,45 @@ namespace OVCCClient
warning ("Trying to connect: %s", e.message);
throw new ServerError.FAILED ("Cannot connect to server");
}
/* login */
send_message (new LoginMessage (player.nick, ""));
/* ... */
try {
msg = Message.receive (input);
} catch (Error e) {
warning ("Failed getting welcome messsage: %s", e.message);
throw new ServerError.COMMUNICATION_FAILED ("Didn't receive welcome");
}
if (msg.message_type != MessageType.WELCOME) {
throw new ServerError.COMMUNICATION_FAILED ("Received invalid message type");
}
debug ("Got welcome from server: %s", (msg as WelcomeMessage).message);
return true;
}
public /*async*/ bool login_to (Player player)
throws ServerError
{
Message msg;
send_message (new LoginMessage (player.nick, "patate"));
try {
msg = Message.receive (input);
} catch (Error e) {
warning ("Failed getting login answer messsage: %s", e.message);
throw new ServerError.COMMUNICATION_FAILED ("Didn't receive login answer");
}
if (msg.message_type != MessageType.LOGIN) {
throw new ServerError.COMMUNICATION_FAILED ("Received invalid message type");
}
if ((msg as LoginMessage).status == LoginMessage.State.ALREADY_EXISTS) {
throw new ServerError.NICKNAME_IN_USE ("");
}
if ((msg as LoginMessage).status == LoginMessage.State.MISSING_AUTHENTICATION) {
throw new ServerError.MISSING_AUTHENTICATION ("");
}
if ((msg as LoginMessage).status != LoginMessage.State.OK) {
throw new ServerError.COMMUNICATION_FAILED ("Invalid login status");
}
return true;
}
......
......@@ -26,6 +26,9 @@ public class Client: Object
protected SocketConnection connection = null;
protected DataInputStream input;
protected DataOutputStream output;
public string login {get; set; default = null;}
public string password {get; set; default = null;}
public Client ()
{
......
......@@ -46,6 +46,45 @@ public class Server: ThreadedSocketService
}
return true;
}
private bool handle_login (LoginMessage msg, Client client)
{
bool ok = true;
if (msg.status != LoginMessage.State.QUERY) {
critical ("got LoginMessage with status different from QUERY");
return false;
}
/* missing authentication check */
if (msg.password == "") {
debug ("rejecting auth as password is empty");
msg.status = LoginMessage.State.MISSING_AUTHENTICATION;
client.send (msg);
return false;
}
/* already existing name check WARNING: lock needed */
lock (this.clients) {
foreach (Client c in this.clients) {
if (c.login == msg.login) {
ok = false;
debug ("rejecting auth as login already connected");
msg.status = LoginMessage.State.ALREADY_EXISTS;
break;
}
}
/* registration */
if (ok) {
debug ("accepting auth for %s", msg.login);
msg.status = LoginMessage.State.OK;
client.login = msg.login;
client.password = msg.password;
}
}
client.send (msg);
return ok;
}
private bool handle_connection (ThreadedSocketService service,
SocketConnection connection,
......@@ -89,8 +128,10 @@ public class Server: ThreadedSocketService
}
switch (msg.message_type) {
case MessageType.LOGIN:
debug ("Login with '%s' and '%s'", (msg as LoginMessage).login,
debug ("Login for '%s' with '%s'", (msg as LoginMessage).login,
(msg as LoginMessage).password);
handle_login ((msg as LoginMessage), client);
break;
case MessageType.DISCONNECT: running = false; break;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment