Posible bug in Approve( ) ?

81 views
Skip to first unread message

Llorenç Marti

unread,
Sep 16, 2010, 8:18:06 AM9/16/10
to lidgren-network
Hi Michael.

First of all, remember that i still use Lidgren.Network v2.

Yesterday my server crashed and the stacktrace showme where was the
error:

Mensaje de Error: Ya se agregó un elemento con la misma clave.
Hora: 15/09/2010 8:21:32 02:00:00
Nombre de la Funcion: Void
ThrowArgumentException(System.ExceptionResource)
StackTrace: en
System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
en System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue
value, Boolean add)
en System.Collections.Generic.Dictionary`2.Add(TKey key, TValue
value)
en Lidgren.Network.NetServer.AddConnection(Double now,
NetConnection conn)
en Lidgren.Network.NetConnection.Approve(Byte[] localHailData)
en Lidgren.Network.NetConnection.Approve()
en BiworldServer.BwServer.CheckNewClient(NetConnection inSender,
String inLogin, String inPass, Vector3f inIniPos, Single inOri,
AvatarData inAvDat)
en BiworldServer.BwServer.ProcessApproval(NetBuffer inBuffer,
NetConnection inSender)
en BiworldServer.BwServer.Update()
en BiworldServer.Program.Main(String[] args)

I'm dont have any more information, but i can see that Approve( )
function try to insert a key previously inserted on a Dictionary, and
ofcourse, i dont know if it is my fault. If i call Approve( ) 2 times
one after another in the same connection, will i have this kind of
error ?

Hopes it help you with your improvement of the lib.

LLORENS

Chris

unread,
Sep 16, 2010, 10:47:53 AM9/16/10
to lidgren...@googlegroups.com, lidgren-network
I've seen the same error. I went through the code and checked for an
existing key before inserting. I think it was a total of two places.

If the key exisits I just drop it. I've had no problems since.

> --
> You received this message because you are subscribed to the Google
> Groups "lidgren-network" group.
> To post to this group, send email to lidgren...@googlegroups.com.
> To unsubscribe from this group, send email to lidgren-netwo...@googlegroups.com
> .
> For more options, visit this group at http://groups.google.com/group/lidgren-network?hl=en
> .
>

lidgren

unread,
Sep 16, 2010, 2:19:30 PM9/16/10
to lidgren-network
Good catch. Fixed in revision 290.

--micahel

On Sep 16, 4:47 pm, Chris <mad...@gmail.com> wrote:
> I've seen the same error. I went through the code and checked for an  
> existing key before inserting. I think it was a total of two places.
>
> If the key exisits I just drop it. I've had no problems since.
>

Llorenç Marti

unread,
Sep 28, 2010, 3:56:48 AM9/28/10
to lidgren-network
Hi Michael, and sorry for being anoying :) but today i received
another exception about AddConnection( ) function, i think it is
related to the previous problem with Approve( ), but i don't know.

I am using version 290 of Lidgren.Network (gen2)

Mensaje de Error: Ya se agregó un elemento con la misma clave.
Hora: 27/09/2010 17:55:02 02:00:00
Nombre de la Funcion: Void
ThrowArgumentException(System.ExceptionResource)
StackTrace: en
System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
en System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue
value, Boolean add)
en System.Collections.Generic.Dictionary`2.Add(TKey key, TValue
value)
en Lidgren.Network.NetServer.AddConnection(Double now,
NetConnection conn)
en BiworldServer.BwServer.CheckNewClient(NetConnection inSender,
String inLogin, String inPass, Vector3f inIniPos, Single inOri,
AvatarData inAvDat)
en BiworldServer.BwServer.ProcessApproval(NetBuffer inBuffer,
NetConnection inSender)
en BiworldServer.BwServer.Update()
en BiworldServer.Program.Main(String[] args)

Hope it helps you. Don't forget to see that in this last StackTrace,
there is no Approve( ) call at all, is this correct ?

I can show you how 'CheckNewClient' function is coded:

/// <summary>
/// Funcion que segun una nueva conexion, nos indica si debemos
aprovarla o no. Estas decisiones se toman segun los datos
/// proporcionados por el cliente y el estado logico anterior de este
cliente
/// </summary>
/// <param name="inSender">Conexion del nuevo cliente</param>
/// <param name="inLogin">Nombre de este cliente</param>
/// <param name="inPass">Password de ese cliente</param>
/// <param name="inIniPos">Posicion inicial del cliente</param>
/// <param name="inOri">Orientacion inicial</param>
/// <param name="inAvDat">Informacion del avatar del personaje</param>
void CheckNewClient(NetConnection inSender, String inLogin, String
inPass, Vector3f inIniPos,float inOri, AvatarData inAvDat)
{
ushort ClientID;

if(m_LoginRelation.TryGetValue(inLogin, out ClientID))
{
// Si el nombre ya esta en nuestra tabla de relaciones quiere decir
que el cliente YA esta conectado.
// Debemos comprobar el pass, si es igual, entonces desconectamos la
conexion anterior y la substituimos
// por la actual.

// Recuperamos la informacion del cliente
ClientData CData;
if(m_ClientsBag.TryGetValue(ClientID, out CData))
{
// Accedemos a la base de datos y recuperamos la informacion de
login para comparar datos

uint iID;
String sName;
String sHash;

CData.Position = inIniPos;
CData.Orientation = inOri;
CData.Avatar = inAvDat;

if (m_DBHelper.GetLoginInfo(inLogin, out iID, out sName, out
sHash))
{

bool bSamePass = CheckPasswordIntegrity(inPass, sHash);

if (bSamePass)
{

if (CData.IsInThisServer)
{
// Si el password es el mismo, el cliente legitimo esta
intentando hacer login desde otro lugar o sesion
// Debemos desconectar la anterior conexion y substituirla por
la actual.
CData.ID = (ushort)iID;
ClientIndentifier CliIdentDisc = new
ClientIndentifier(ushort.MaxValue, false);
CData.Connection.Tag = CliIdentDisc; // Marcamos la conexion
como una conexion sin Client Data asociado
CData.Connection.Disconnect("Login from other site/session",
1.0f);
CData.Connection = inSender; // Guardamos la nueva conexion en
el mismo Client Data.
ClientIndentifier CliIdentNew = new
ClientIndentifier((ushort)iID, false);
CData.Connection.Tag = CliIdentNew;
CData.ServerOwnerIP = null;

CData.Connection.Approve(); // Aprovamos la nueva conexion
//Console.WriteLine(CData.Login + " approved again.");
m_SrvLog.Info(CData.Login + " aprobado otra vez.");
}
else
{
// Debemos buscar el server A al que pertenece el cliente A para
indicarle que el cliente A quiere conectarse con nosotros
// y debera ser desconectado del server A


CData.Connection = inSender;
ClientIndentifier CliIdentDisc = new
ClientIndentifier((ushort)iID, false);
CData.Connection.Tag = CliIdentDisc;
CData.IsInThisServer = true;
CData.ServerOwnerIP = null;
CData.Connection.Approve();
//Console.WriteLine(CData.Login + "now approved in this
server");
m_SrvLog.Info(CData.Login + " ahora aprobado en este
servidor.");

// Necesario mandar aqui la desconexion forzada en los demas
servidores ?

}

}
else
{
// Si el password no es el mismo, tenemos a un cliente NO
legitimo intentando hacer login en una cuenta sin
// saber su password, no debemos aceptar la conexion.

inSender.Disapprove("Password missmatch!");
//Console.WriteLine("Internal error with " + inLogin + " and pass
missmatch, disapproved.");
m_SrvLog.Error(inLogin + " intenta entrar con un password
incorrecto, disapproved!");
}
}
else
{
inSender.Disapprove("Login failed!");
//Console.WriteLine("No existe el login: "+ inLogin);
m_SrvLog.Error("No existe el login: " + inLogin);
}
}
else
{
// Error, tenemos una relacion NombreCliente - ID, pero no tenemos
el ID - ClientData
// Tenemos que crear un nuevo ClientData

uint iID;
String sName;
String sHash;

// Recuperamos los datos de la BBDD
if (m_DBHelper.GetLoginInfo(inLogin, out iID, out sName, out
sHash))
{
// Comprobamos la integridad del password
bool bSamePass = CheckPasswordIntegrity(inPass, sHash);

if (bSamePass)
{
// Si el password es correcto, entonces creamos un nuevo cliente
pues no estaba insertado
// !!! Este caso es especial y no tendria que darse nunca
ClientData NewClient = new ClientData();
NewClient.Position = inIniPos;
NewClient.Orientation = inOri;
NewClient.Avatar = inAvDat;
NewClient.Connection = inSender;
NewClient.ID = (ushort)iID;
ClientIndentifier CliIdentNew = new
ClientIndentifier((ushort)iID, false);
NewClient.Connection.Tag = CliIdentNew;
NewClient.Login = inLogin;
NewClient.Name = sName;
NewClient.ServerOwnerIP = null;
//NewClient.Password = inPass;
m_ClientsBag.Add(ClientID, NewClient);

NewClient.Connection.Approve(); // Aprovamos la conexion
//Console.WriteLine("Internal error with " + inLogin + ",
aproved");
m_SrvLog.Error("Caso extraordinario con " + inLogin + ",
aprobado.");
}
else
{
inSender.Disapprove("Password missmatch!");
//Console.WriteLine("Internal error with " + inLogin + " and pass
missmatch, disapproved.");
m_SrvLog.Error(inLogin + " intenta entrar con password
incorrecto, disapproved.");
}
}
else
{
inSender.Disapprove("Login failed!");
//Console.WriteLine("Internal error with " + inLogin + " and login
failed, disapproved.");
m_SrvLog.Error(inLogin + " intenta entrar con Login incorrecto,
disapproved.");
}
}
}
else
{
// Si el nombre no esta en nuestra base de datos, entonces es que no
tenemos a este clietne conectado anteriormente
// Guardaremos sus datos en un Client Data y aceptaremos su conexion

uint iID;
String sName;
String sHash;

// Recuperamos los datos de la BBDD
if (m_DBHelper.GetLoginInfo(inLogin, out iID, out sName, out sHash))
{
// Comprobamos la integridad del password
bool bSamePass = CheckPasswordIntegrity(inPass, sHash);

if (bSamePass)
{
ClientData NewClient = new ClientData();
NewClient.Position = inIniPos;
NewClient.Orientation = inOri;
NewClient.Avatar = inAvDat;
NewClient.Connection = inSender;
NewClient.ID = (ushort)iID;
ClientIndentifier CliIdentNew = new ClientIndentifier((ushort)iID,
false);
NewClient.Connection.Tag = CliIdentNew;
NewClient.Login = inLogin;
NewClient.Name = sName;
NewClient.ServerOwnerIP = null;
//NewClient.Password = sHash;
m_ClientsBag.Add((ushort)iID, NewClient);
m_LoginRelation.Add(inLogin, (ushort)iID);

NewClient.Connection.Approve(); // Aprovamos la conexion
//Console.WriteLine(NewClient.Login + ":" + sName + " approved
(new)");
m_SrvLog.Info(NewClient.Login + ":" + sName + " aprobado. (new)");
}
else
{
inSender.Disapprove("Password missmatch!");
//Console.WriteLine("New login password missmatch: " + inLogin);
m_SrvLog.Error("Nuevo Login Password Incorrectos: " + inLogin);
}
}
else
{
inSender.Disapprove("Login failed!");
//Console.WriteLine("No existe el login: " + inLogin);
m_SrvLog.Error("No existe el login: " + inLogin);
}
}
}

I found it strange becaus i only call Approve( ) and Disapprove( ) on
this code, i dont know why they doesnt be in Stack Trace.

Thanks for your help :)

LLORENS

lidgren

unread,
Sep 28, 2010, 4:24:57 PM9/28/10
to lidgren-network
Hi!

I don't know why Approve() doesn't appear in your callstack, it's very
strange.

I've checked in a change which might help your problem, but you should
probably investigate the underlying issue if possible.

--michael

ArKangeL ArK

unread,
Sep 29, 2010, 5:58:59 AM9/29/10
to lidgren...@googlegroups.com
Hi Michael

Which change did you made on code ?, or maybe there is not yet on the svn, because i still see revision 290 with no changes.

In the same way, do you think it will be positive if i put on servers the debug version of the lidgren.network lib ? May it help with correctness of stacktrace's ? I dont know if the left of Approve( ) on the stacktrace is due to a release version that doesnt contain much info. about debug data.

Thanks for your help.

LLORENS

lidgren

unread,
Sep 29, 2010, 7:43:35 AM9/29/10
to lidgren-network
Hmm... checkin must have failed. I just changed the last line in
AddConnection()...

m_connectionLookup.Add(conn.m_remoteEndPoint, conn);

... to...

m_connectionLookup[conn.m_remoteEndPoint] = conn;

--micahel

ArKangeL ArK

unread,
Sep 29, 2010, 8:24:48 AM9/29/10
to lidgren...@googlegroups.com
Thanks Michael, i will check f it crashes or not :)

LLORENS
Reply all
Reply to author
Forward
0 new messages