Steamworks.NET icon indicating copy to clipboard operation
Steamworks.NET copied to clipboard

ValidateAuthTicektResponce_t doesn't callback on servers

Open JamesMcGhee opened this issue 3 years ago • 36 comments

When we initialize as SteamGameServer and call BeginAuthSession The ValidateAuthTicektResponce_t never responds

We have been doing a lot of troublshooting on this and I finally took the mind to check the definitions ... I noted that there is no SteamGameServer version of this callback there is only the one ValidateAuthTicektResponce_t defined in SteamCallbacks.cs and that definition sets the callback ID as

public const int k_iCallback = Constants.k_iSteamUserCallbacks + 43;

should there be a GameServerValidateAuthTicketResponce_t where in

public const int k_iCallback = Constants.k_iSteamGameServerCallbacks + 43;

If that is the case it would explain why we dont get the callback as expected and would sugest there is also an issue with GetAuthSessionTicketResponse_t similar thing ... should have a GameServer variant

Then again I could be insain and something else is preventing the callback from returning but this works perfrectly on the Client API should be the same code for Server the only difference being

SteamGameServer.BeginAuthSession

as oppsed to

SteamUser.BeginAuthSession

JamesMcGhee avatar May 31 '22 14:05 JamesMcGhee

@rlabrecque Think I have 5 clients now effected by this.

In all cases its down to the SteamGameServer.BeginAuthSession not getting the ValidateAuthTicektResponce_t

The SteamUser.BeginAuthSession does get the ValidateAuthTicektResponce_t callback

JamesMcGhee avatar Jun 01 '22 08:06 JamesMcGhee

Highly waiting to know how to fix that also ! :)

francoios avatar Jun 01 '22 09:06 francoios

Also having this problem, will be waiting, thanks.

Jusremo avatar Jun 03 '22 14:06 Jusremo

Me too! 👍

XuX26 avatar Jun 03 '22 14:06 XuX26

Might as well throw my name in there ;)

TXMerc avatar Jun 03 '22 17:06 TXMerc

I won't be able to check this out for at least a couple more days, but if you duplicate ValidateAuthTicektResponce_t (even into your project) and change the k_iCallback, then register that new callback, does that work?

rlabrecque avatar Jun 03 '22 18:06 rlabrecque

All the users on my side would be using Package Manager install They can modify the code but need to do that in the package cashe within the project ... half the point of Package Manager is no in advertently changing the code :)

I'll check with a couple of them in our Discord see how it goes and update you

JamesMcGhee avatar Jun 04 '22 22:06 JamesMcGhee

For anyone looking to do it

You simply need to create a new responce type such as

[StructLayout(LayoutKind.Sequential, Pack = 4)]
[CallbackIdentity(Constants.k_iSteamGameServerCallbacks + 43)]
public struct GameServerValidateAuthTicketResponse_t 
{
        public const int k_iCallback = Constants.k_iSteamGameServerCallbacks + 43;
        public CSteamID m_SteamID;
        public EAuthSessionResponse m_eAuthSessionResponse;
        public CSteamID m_OwnerSteamID; // different from m_SteamID if borrowed
}

Then you need to modify Heathen's Authentication API as follows

On line 40 change this

private static Callback<ValidateAuthTicketResponse_t> m_ValidateAuthSessionTicketResponceServer;

to this

private static Callback<GameServerValidateAuthTicketResponse_t> m_ValidateAuthSessionTicketResponceServer;

then on line 138 change this

m_ValidateAuthSessionTicketResponceServer = Callback<ValidateAuthTicketResponse_t>.Create(HandleValidateAuthTicketResponse);

to this

m_ValidateAuthSessionTicketResponceServer = Callback<GameServerValidateAuthTicketResponse_t>.Create(HandleGameServerValidateAuthTicketResponse);

finally add the following method above line 184

private static void HandleGameServerValidateAuthTicketResponse(GameServerValidateAuthTicketResponse_t param)
{
    if (ActiveSessions != null && ActiveSessions.Any(p => p.User == param.m_SteamID))
    {
        var session = ActiveSessions.First(p => p.User == param.m_SteamID);
        session.Authenticate(param);

        if (SteamSettings.current != null && SteamSettings.current.isDebugging)
            Debug.Log("Processing session request data for " + param.m_SteamID.m_SteamID.ToString() + " status = " + param.m_eAuthSessionResponse);

        if (param.m_eAuthSessionResponse != EAuthSessionResponse.k_EAuthSessionResponseOK)
            ActiveSessions.Remove(session);

        if (session.OnStartCallback != null)
            session.OnStartCallback.Invoke(session);
    }
    else
    {
        if (SteamSettings.current != null && SteamSettings.current.isDebugging)
            Debug.LogWarning("Recieved an authentication ticket responce for user " + param.m_SteamID.m_SteamID + " no matching session was found for this user.");
    }
}

Those steps are untested at current, I am working with others in a ticket on the Discord server to get this tested out. If you do this and have any issues ... or find it works please let us know.

JamesMcGhee avatar Jun 04 '22 22:06 JamesMcGhee

Initial testing isn't a hit .. yet ... still playing with it @rlabrecque

where is it exsactly that you source the value to add to the constant ... e.g. in the following

[StructLayout(LayoutKind.Sequential, Pack = 4)]
[CallbackIdentity(Constants.k_iSteamUserCallbacks + 43)]
public struct ValidateAuthTicketResponse_t {
	public const int k_iCallback = Constants.k_iSteamUserCallbacks + 43;
	public CSteamID m_SteamID;
	public EAuthSessionResponse m_eAuthSessionResponse;
	public CSteamID m_OwnerSteamID; // different from m_SteamID if borrowed
}

Where did you get 43 from? We are assuming that the GameServer version will be a + 43 just like the client but that is a blind assumption

JamesMcGhee avatar Jun 05 '22 00:06 JamesMcGhee

I'm starting to wonder if I've just lost it or what. I want to make sure with y'all I'm understanding the documentation correctly so we're not going down the wrong path(still lacking a callback being called either way though). It actually says 2 different things when you read it.

Important Links: https://partner.steamgames.com/doc/features/auth https://partner.steamgames.com/doc/api/ISteamUser#BeginAuthSession https://partner.steamgames.com/doc/api/steam_api#EBeginAuthSessionResult https://partner.steamgames.com/doc/api/ISteamUser#ValidateAuthTicketResponse_t

So basic order of things should be:

  • Client gets a ticket
  • Client passes ticket to the server
  • Server calls BeginAuthSession
  • EBeginAuthSessionResult is immediately returned (no callback like auth page mentions).
  • It then registers the callback for ISteamUser:ValidateAuthTicketResponse in the event a user goes offline/cancels ticket
  • As long as we get k_EBeginAuthSessionResulOK then the user is approved to move forward.

When a user disconnects we call EndAuthSession and the callback above is supposed to be called right?

Here is where things got weird in the docs -- The auth page says it will perform the check and then call ISteamUser:ValidateAuthTicketResponse with the results. But then the BeginAuthSession page says it returns a EBeginAuthSessionResult(which is working properly) and that ValidateAuthTicketResponse_t is used if a entity goes offline or cancels the ticket(does not work).

For now I'm assuming the BeginAuthSession page is correct and that the auth page is misleading/wrong. As I keep poking around I'll update this with anything I think might be helpful.

TXMerc avatar Jun 05 '22 02:06 TXMerc

The workflow is this

  1. entity (user) generates a ticket
  2. entity sends said ticket along with the entiteis CSteamID to that which is going to validate them (can be a server or another user)
  3. That authenticating entity (server or other user) calls BeginSession ... now which is called depends on if this authenticating entity is a Steam Game Server or a user e.g. SteamUser.BeginAuthSession(authTicket, authTicket.Length, user); would be called by the client e.g. when a user is validating another user and SteamGameServer.BeginAuthSession(authTicket, authTicket.Length, user); would be called by a Steam Game Server when authenticating a user

So the callbacks need to already be registered

That is the entity doing the authenticating (server or client) needs to already have registered the callback on Callback<ValidateAuthTicketResponse_t>.Create(handler); before the BeginAuthSession is called

PS the whole reason for this issue is that the Steam Game Server isn't getting the callback ... so it wont work there

It does work when you have a user authenticate a user that is the

SteamUser.BeginAuthSession(authTicket, authTicket.Length, user); does result in ValidateAuthTicketResponse_t callback but SteamGameServer.BeginAuthSession(authTicket, authTicket.Length, user); does not result in callback

This all works as expected and as documented

I think your getting confused in that BeginAuthSession does return a EBeginAuthSessionResult that simply indicates a fundamental issue/error ... the callback on ValidateAuthTicketResponse_t will still occur and will carry additional data in the ValidateAuthTicketResponse_t mainly the EAuthSessionResponse note that EAuthSessionResponse is the response to the request and tells you more than EBeginAuthSessionResult

Or at least this is how I have been using it for some time now though I typically and authenticating a user vai another user such as in P2P networking sessions so I haven't previously ran into the issue with Steam Game Server where it does not get the ValidateAuthTicketResponse_t response

Point is the EBeginAuthSessionResult is not the same as the EAuthSessionResponse EBeginAuthSessionResult is returned immeadtly when you call BeginAUthSession and simply indicates that the request was sent off to Steam API or if not why not EAuthSessionResponse is present in the response ValidateAuthTicketResponse_t which comes as a callback when the Auth Session has been processed

Just to reword that

EBeginAuthSessionResult.k_EBeginAuthSessionResultOK = Ticket is valid for this game and this Steam ID. so this is just saying yes this ticket is structurally a valid ticket for this game

in contrast

EAuthSessionResponse.k_EAuthSessionResponseOK which comes in on the callback is Steam has verified the user is online, the ticket is valid and ticket has not been reused. so this is saying the ticket is valid, belongs to this user for this game and this user is online ... e.g. everything is legit here drive on

JamesMcGhee avatar Jun 05 '22 11:06 JamesMcGhee

@rlabrecque So I did some more digging to understand what k_iCallback was/is

I think I understand that it simply needs to be a unique ID such that when registering a callback no 2 callbacks have the same ID.

If that is the case then Constants.k_iSteamGameServerCallbacks and the client equivalent values of 100 and 200 are arbitrary and are not responsible for the issue we are seeing in Steam Game Server where the callback is not being returned. So long as the ID is unique which of course it will be since only 1 is ever registered either client or server but never both ... then we know its always unique.

Also I did more digging in the Valve documents

The SteamUser API references that it will trigger the ValidateAuthTicketResponse_t callback

The SteamGameServer API simply says

This registers for ValidateAuthTicketResponse_t callbacks if the entity goes offline or cancels the ticket. See EAuthSessionResponse for more information.

So then is it intended behaviour that Steam Game Server Begin Auth Session does not raise the ValidateAuthTicketResponse_t callback. And if that is the case is that not a glaring issue?

I looked through the Steam Game Server interface callback documentation and do not see a variant of ValidateAuthTicketResponse_t. When I check the header file for SteamUser interface I see the ValidateAuthTicketResponse_t when I check the header for SteamGameServer I do not see an equivalent ... this is really leading me to believe that SteamGameServer BeginAuthSession is just fundamentally different than the workflow seen with SteamUser BeginAuthSession

This really does feel like a bug on Valve's part to me ... but best case its broken documentation on Valve's part Accordingly to the documentation there is no ValidateAuthTicketResponse_t for SteamGameServer interface's BeginAuthSession though it is referenced it is not said it outright triggers it. Without this callback though you cant know if the session is valid and that the user is logged on and how the user is licensed e.g. barrowing, etc. ... unless I am missing something

JamesMcGhee avatar Jun 05 '22 12:06 JamesMcGhee

Some more reading and working on this

I am fairly well convinced now that this is a bug with Steam API ... though not sure how we could be the first to complain about it :)

image

While the documentation for SteamGameServer.BeginAuthSession doesn't explicitly say it triggers the ValidateAuthTicketResponce_t callback ... the EAuthSessionResponce does

So it seems like SteamGameServer.BeginAuthSession is using the ValidateAuthTicketResponce_t which is defined in the SteamUser.h ... which why ... but okay

Also this unless I am mistaken means there is nothing Steamworks.NET is doing wrong here. Its simply that Steam API isn't invoking the callback for SteamGameServer but it does for SteamUser

JamesMcGhee avatar Jun 05 '22 14:06 JamesMcGhee

I have a ticket off to Steam my self but haven't heard back yet

This is still a problem for us and the rest of our users as far as I am aware. Does anyone else have any progress they can share?

JamesMcGhee avatar Jun 13 '22 16:06 JamesMcGhee

Hey James, sorry I haven't really been able to get to this much.

The callback numbers themselves are defined by Steam and are available via the Steamworks API here:

https://github.com/rlabrecque/Steamworks.NET/blob/master/CodeGen/steam/steam_api_internal.h#L247-L290=

It looks like all of the k_iSteamGameServerCallbacks callbacks are defined in isteamgameserver.h:

https://github.com/rlabrecque/Steamworks.NET/blob/f5c8f33c4fc4493f47d9a15c904b7025843c4fc7/CodeGen/steam/isteamgameserver.h#L283=

The callback Id is pretty arbitrary but -- it must match on both sides, it's basically the key to lookup what type of struct to use because Steam basically just sends (callbackId, binaryDataBlob, binaryDataBlobSize) to games, but then we (Steamworks code in the game) have to do deserialization from that blob into an actual struct.

I think one thing to try is enabling log_callbacks in Steam as documented here, would be interesting to see what kind of callbacks are /attempted/ to be sent when we call these functions:

https://partner.steamgames.com/doc/sdk/api/debugging

rlabrecque avatar Jun 13 '22 16:06 rlabrecque

I can try this on Thursday night and let y'all know what happens.

TXMerc avatar Jun 15 '22 02:06 TXMerc

@rlabrecque

Taking a look at the istemgameserver.h again and nothing, it still looks like a bug either with the code which I get is unlikely someone would have hit this by now ... more likely with the documentation

// Authenticate ticket ( from GetAuthSessionTicket ) from entity steamID to be sure it is valid and isnt reused
// Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse )
virtual EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID ) = 0;	

That is the comment in the server about the method in question. That notes the ValidateAuthTicketResponce_t callback which doesn't exist in this header. It only exists in the SteamUser header and starts with 100 being the steam user segment of call-back IDs

The closest thing we have is

struct GSClientApprove_t
{
	enum { k_iCallback = k_iSteamGameServerCallbacks + 1 };
	CSteamID m_SteamID;			// SteamID of approved player
	CSteamID m_OwnerSteamID;	// SteamID of original owner for game license
};


// client has been denied to connection to this game server
struct GSClientDeny_t
{
	enum { k_iCallback = k_iSteamGameServerCallbacks + 2 };
	CSteamID m_SteamID;
	EDenyReason m_eDenyReason;
	char m_rgchOptionalText[128];
};

These are documented as belonging to SendUserConnectAndAuthenticate which has the note

NOTE: This is part of the old user authentication API and should not be mixed with the new API.

This tells me I shouldn't be using this with the AuthSession system ... will have to wait and see what @TXMerc finds in his test

I think worst case we see a callback ID 201 which would be GSClientApprove_t or ID 202 which would be GSClientDeny_t I call this worst case as these do not have the information we would expect and get from the session callback

The other option is we see a callback ID that isn't listed in iSteamGameServerCallbacks ... we know the server callbacks segment on 200 and that 9 are listed covering 1 to 11 skipping 4 and 5.

PS: I noticed something odd in the header ... This is in the isteamgameserver header ... but its using a callback ID on the user segment

// received when the game server requests to be displayed as secure (VAC protected)
// m_bSecure is true if the game server should display itself as secure to users, false otherwise
struct GSPolicyResponse_t
{
	enum { k_iCallback = k_iSteamUserCallbacks + 15 };
	uint8 m_bSecure;
};

Also of those structures that are prefixed with k_iSteamGameServerCallbacks they count { 1, 2, 3, 6, 7, 8, 9, 10, 11 }

So 4 and 5 are skipped and we see a "15" in the game server header that is just out of place all together.

JamesMcGhee avatar Jun 15 '22 09:06 JamesMcGhee

@rlabrecque log_callbacks is a Steam Client command line, the issue is the Steam Game Server callback ... so far we haven't been able to find a way to log the callbacks for the server

We gave it a go with Steam CMD and aren't seeing any thing from the log_callback command ... any ideas?

JamesMcGhee avatar Jun 19 '22 13:06 JamesMcGhee

Still nothing on this one, no response from Valve, no results from attempting to log callbacks

JamesMcGhee avatar Jun 25 '22 10:06 JamesMcGhee

I have had a ticket open with Valve for 20 days now and no response :) that's a record for me.

I have started a forum post ... course Steamworks developer forum is in my experience completely useless generally no one responds https://steamcommunity.com/groups/steamworks/discussions/1/3409802983878249925/

I am completely out of ideas on this one

JamesMcGhee avatar Jun 25 '22 10:06 JamesMcGhee

Still looking for any support we can on this one.

Its been exactly one month since I reached out to Valve ... still no initial response from them. Posted on the Steamworks Developer forum and no response there at all either

Any ideas at all are welcome

JamesMcGhee avatar Jul 03 '22 15:07 JamesMcGhee

Just checking in on this one again

Still no word from Valve on my side nor the Steamworks Developer community

Help me @rlabrecque your our only hope :) Star Wars reference but seriously any help you can offer or maybe any ideas on where else to search would be greatly appreciated

JamesMcGhee avatar Jul 16 '22 15:07 JamesMcGhee

Yep kinda annoying that Valve etc putting this issue under the carpet

francoios avatar Jul 16 '22 17:07 francoios

Coming up on 2months now no response from Valve not even an initial response, to the point I submitted a support case about my support case to see if Valve even does support anymore.

Anyway

I think from our point of view we are going to have to say Steamworks.NET doesn't support Steam Game Server at least not fully.

Would be very happy to help work on this in the future if anyone is keen to engage, happy to pay as well.

JamesMcGhee avatar Jul 23 '22 16:07 JamesMcGhee

I just added another comment to my ticket as well. I'll let y'all know if I get anything but so far I've been surprised, even wowed at how unresponsive they are.

TXMerc avatar Jul 24 '22 13:07 TXMerc

It is an unusual level of unresponsiveness. I am used to them taking a few days maybe a week but this is 2 months and not even an initial response

JamesMcGhee avatar Jul 25 '22 07:07 JamesMcGhee

@rlabrecque ? any news ?

francoios avatar Jul 29 '22 17:07 francoios

I poked around Facepunch and best I can see they aren't doing anyhting different but I am told it works through them

I confirmed the callback ID as well 143 rather its on client server that is just the callback ID

JamesMcGhee avatar Jul 31 '22 13:07 JamesMcGhee

@rlabrecque any idea why Valve has stopped responding to support requests. I submitted a ticket well more than 2 months ago at this point. I have updated it just once a week or so with new testing results, etc. but I still haven't gotten an initial response from them.

To my knowledge none of the devs I have been working with on this issue has gotten a response either.

JamesMcGhee avatar Aug 11 '22 21:08 JamesMcGhee

I haven't been able to look deeper yet unfortunately.

Do we have a minimal repro of this, and has anyone tried recreating it with the C++ SDK?

rlabrecque avatar Aug 12 '22 05:08 rlabrecque