Puzzle failing
by Anthony Lovell · in Torque Game Engine · 07/10/2006 (6:41 am) · 8 replies
Both client and server interface are set to require key exchange, and the connect() from the client connection specifies that keys be exchanged but no certs be used. Each app has 2 interfaces... only the first for each is being used.
FWIW, a little time in the debugger indicated "Invalid Client Nonce"as the puzzle failure reason.
Can anyone tell what seems to be wrong?
The server's log :
The client's log :
FWIW, a little time in the debugger indicated "Invalid Client Nonce"as the puzzle failure reason.
Can anyone tell what seems to be wrong?
The server's log :
Winsock initialization succeeded. LogUDP: UDP socket created - bound to address: IP:Any:52821 LogUDP: UDP socket receive buffer size set to 32768. LogUDP: UDP socket send buffer size set to 32768. LogUDP: UDP socket non-blocking IO set. Socket initialized. LogNetBase: Class Group: 0 Class Type: 2 count: 3 LogNetBase: RPC_GhostConnection_rpcEndGhosting LogNetBase: RPC_GhostConnection_rpcReadyForNormalGhosts LogNetBase: RPC_GhostConnection_rpcStartGhosting LogNetInterface: Received Connect Challenge Request from IP:127.0.0.1:2437 LogNetInterface: Sending Challenge Response: df793a21 Timer: secretSubKeyGen Elapsed: 340.172 ms LogNetInterface: Received Connect Request df793a21 LogNetInterface: Received Connect Challenge Request from IP:127.0.0.1:2437 LogNetInterface: Sending Challenge Response: cd3ecc85 Timer: secretSubKeyGen Elapsed: 254.168 ms LogNetInterface: Received Connect Request cd3ecc85
The client's log :
Winsock initialization succeeded. LogUDP: UDP socket created - bound to address: IP:Any:2437 LogUDP: UDP socket receive buffer size set to 32768. LogUDP: UDP socket send buffer size set to 32768. LogUDP: UDP socket non-blocking IO set. Socket initialized. LogNetBase: Class Group: 0 Class Type: 2 count: 3 LogNetBase: RPC_GhostConnection_rpcEndGhosting LogNetBase: RPC_GhostConnection_rpcReadyForNormalGhosts LogNetBase: RPC_GhostConnection_rpcStartGhosting LogNetInterface: Sending Connect Challenge Request to IP:127.0.0.1:52821 Timer: secretSubKeyGen Elapsed: 273.24 ms LogNetInterface: Received Challenge Response: df793a21 Client puzzle solved in 2657 ms. LogNetInterface: Sending Connect Request LogNetInterface: Sending Connect Request LogNetInterface: Received Connect Reject - reason Puzzle LogNetInterface: Sending Connect Challenge Request to IP:127.0.0.1:52821 Timer: secretSubKeyGen Elapsed: 222.451 ms LogNetInterface: Received Challenge Response: cd3ecc85 Client puzzle solved in 859 ms. LogNetInterface: Sending Connect Request LogNetInterface: Sending Connect Request LogNetInterface: Received Connect Reject - reason Puzzle
#2
07/22/2006 (11:10 pm)
What now? Putting the connection class in a namespace broke it?
#3
The last part attempts to prepend a "g" to the class name in hopes of making it clear the static is a global variable. If I qualified my connection class with my namespace, this broke for obvious reasons: gMyNameSpace::MyConnection is not a valid namespace. When I omitted MyNameSpace::, I was finding that it did not work. I'd have to run another test to see why this was.
At any rate, I am off and running and fairly happy.
tone
07/23/2006 (6:45 am)
I think so. The last part attempts to prepend a "g" to the class name in hopes of making it clear the static is a global variable. If I qualified my connection class with my namespace, this broke for obvious reasons: gMyNameSpace::MyConnection is not a valid namespace. When I omitted MyNameSpace::, I was finding that it did not work. I'd have to run another test to see why this was.
At any rate, I am off and running and fairly happy.
tone
#4
07/23/2006 (11:41 am)
Did you call the macro from the same namespace as the class?
#5
I sidestepped the issue, but still cannot get the connections coming up owing (I think) to a dissimilar number of net classes on each side of the connection and some suspect code I see (snarky comments inserted below)
Essentially, I think the code above has a bug in that the server decides to use the lesser of two counts rather than the greater one. But I also have a major question about this "version border count" -- can it just crawl into the bushes and die?
tone
08/11/2006 (9:22 am)
Carter... I'm not sure.I sidestepped the issue, but still cannot get the connections coming up owing (I think) to a dissimilar number of net classes on each side of the connection and some suspect code I see (snarky comments inserted below)
bool EventConnection::readConnectRequest(BitStream *stream, const char **errorString)
{
if(!Parent::readConnectRequest(stream, errorString))
return false;
U32 classCount;
stream->read(&classCount);
U32 myCount = NetClassRep::getNetClassCount(getNetClassGroup(), NetClassTypeEvent);
// WAIT!?!? Why is the check below <= and not >= ?
// shouldn't both sides of this transaction consider the number of netclasses that must
// be identified across it as being the GREATER of the two counts, and not the lesser?
if(myCount <= classCount)
mEventClassCount = myCount;
else
{
mEventClassCount = classCount;
// I have utterly no idea what "version border count" is supposed to mean
// at any rate, this is the check which is failing on my server, and the false return
// value is what causes my connections to fail. Can someone explain what this check
// is supposed to do?
if(!NetClassRep::isVersionBorderCount(getNetClassGroup(), NetClassTypeEvent, mEventClassCount))
return false;
}
mEventClassVersion = NetClassRep::getClass(getNetClassGroup(), NetClassTypeEvent, mEventClassCount-1)->getClassVersion();
mEventClassBitSize = getNextBinLog2(mEventClassCount);
return true;
}Essentially, I think the code above has a bug in that the server decides to use the lesser of two counts rather than the greater one. But I also have a major question about this "version border count" -- can it just crawl into the bushes and die?
tone
#6
08/12/2006 (4:33 pm)
So the idea of the version border count is that if you release a client that is version 1 and then subsequently upgrade the server, and implement some new net events, that the server can still talk to old clients by not sending it any messages that use the new NetEvent classes. That's why it uses the lesser of the two counts -- but it has to make sure that the number of event classes is on the border between versions i.e. that the server doesn't think there are 30 version 1 events and the client thinks there are 25. Does this make sense?
#7
I should point out that I did not interpret "count" as meaning the number of classes of a certain version level but the total number of classes implemented. This impression was cemented by the use of the logic "mEventClassBitSize = getNextBinLog2(mEventClassCount);" where I thought the two sides were trying to agree on the raw number of entities that would have to be identified by a number, and so naturally I assumed they'd settle on the larger number of entities known by either of them.
My design is different than most in that I have 4 apps that connect in 5 different ways:
AuthServer -- acts as server to PlayerClient and WorldServer
WorldServer -- acts as client to AuthServe and as server to PlayerClient and ShipServer
ShipServer -- acts as client to WorldServer and as server to PlayerClient
PlayerClient -- acts as client to AuthServer, WorldServer, and ShipServer
In all, that is five different interfaces (player to the 3 others, world to auth, and ship to world). If the issue is that I need to make sure that all linked executables lock in code for all net objects, even if they never see them during runtime, I could try to do that, but I'd prefer if the TNL design permitted me to register the netobject classes not globally, but to the NetConnection subclasses that they will actually have to traverse.
tone
PS: I wrote out the function in long-hand to help me understand it (even though I may still be misunderstanding it). Here is my interpretation with comments.
08/13/2006 (6:50 am)
Not really in this case, as ALL my objects are version 1: there just seem to be a dissimilar number declared on both sides of this interface. I should point out that I did not interpret "count" as meaning the number of classes of a certain version level but the total number of classes implemented. This impression was cemented by the use of the logic "mEventClassBitSize = getNextBinLog2(mEventClassCount);" where I thought the two sides were trying to agree on the raw number of entities that would have to be identified by a number, and so naturally I assumed they'd settle on the larger number of entities known by either of them.
My design is different than most in that I have 4 apps that connect in 5 different ways:
AuthServer -- acts as server to PlayerClient and WorldServer
WorldServer -- acts as client to AuthServe and as server to PlayerClient and ShipServer
ShipServer -- acts as client to WorldServer and as server to PlayerClient
PlayerClient -- acts as client to AuthServer, WorldServer, and ShipServer
In all, that is five different interfaces (player to the 3 others, world to auth, and ship to world). If the issue is that I need to make sure that all linked executables lock in code for all net objects, even if they never see them during runtime, I could try to do that, but I'd prefer if the TNL design permitted me to register the netobject classes not globally, but to the NetConnection subclasses that they will actually have to traverse.
tone
PS: I wrote out the function in long-hand to help me understand it (even though I may still be misunderstanding it). Here is my interpretation with comments.
// Returns true if the given class count is on a version boundary
inline bool NetClassRep::isVersionBorderCount(U32 classGroup, U32 classType, U32 count)
{
// siz appears to be the number of classes of a given variety defined in the local app
// that may be used in a given phase of game play, e.g.:
// mClassTable[NetClassGroupGame][NetClassTypeEvent].size()
// tells us "how many NetEvents are declared that are used when the game is fully interactive?"
S32 siz = mClassTable[classGroup][classType].size();
// does our count of such classes match that the remote app has reported?
bool countEqualsSize = count == U32(siz);
// if yes, we are happy
if (countEqualsSize)
return true;
// I really have no idea why this equates to FALSE
if (count == 0)
return false;
// what is the version of the last class declared?
S32 countVer = mClassTable[classGroup][classType][count]->getClassVersion();
// what is the version of the second-to-last class declared?
S32 countMinusOneVer = mClassTable[classGroup][classType][count - 1]->getClassVersion();
// are they of different versions?
bool versionBorderCount = (countVer != countMinusOneVer);
return versionBorderCount;
}
#8
08/13/2006 (11:32 am)
You can specify a net class group mask that will specify what types of connections a given class can be transmitted over. so you don't have to make every class transmittable by every connection. Look for NetClassGroupGameMask, etc to get an idea of how this works.
Torque Owner Anthony Lovell
The big thing that tripped me up was the fragility of the TNL_IMPLEMENT_NETCONNECTION macro, which did not like that my NetConnection subclass was in a namespace. Can we lock the person who created the preprocessor and the C++ namespace idea in a room with a rusty knife and only let one out?
tone