question

GregTinney-2719 avatar image
0 Votes"
GregTinney-2719 asked GregTinney-2719 commented

Web PubSub Connect fails when using FWebSocketsModule library and GenerateClientAccessUri in WebPubSub SDK

Hi,

I'm trying to implement a WebPubSub client in a video game using UE4 game engine's FWebSocketsModule C++ class, which links with libWebSockets library.

When I use a "Client Access URL" from Azure WebPubSub Dashboard's "Client URL Generator", and open the WebSocket with

        FWebSocketsModule::Get().CreateWebSocket(PubSubURL, TEXT(""))

everything works fine. The game code successfully connects to the WebSocket and can receive PubSub events a subscriber on the hub.

126059-image.png

However, when I don't use this "Client URL Generator" devtool to generate the WebSocket url, but instead generate it using the WebPubSub SDK to in a C# app:

       var serviceClient = new WebPubSubServiceClient(Connections.ConnectionString, TEXT("Hub"));
       var connectURL = serviceClient.GenerateClientAccessUri(userId: "player1234");
       return connectURL.ToString();

where Connections.ConnectionString is the "ConnectString" provided in the WebPubSub dashboard, then my game's

       FWebSocketsModule::Get().CreateWebSocket(PubSubURL, TEXT(""))

operation fails. Since FWebSocketsModule uses a binary library, I don't get complete insight into the failure cause, though I do know I receive a "401 Unauthorized" response from the WebSocket server, so I assume the WebSocket upgrade failed. Unfortunately, since the Azure PubSub service uses wss/secured WebSockets, I can't use WireShark to review the WebSocket upgrade handshaking.

Further confounding the issue, however, is that, if I use that exact same PubSubUrl I generated to open a connection from a C# using the ClientWebSocket() object, the WebSocket connection succeeds, and the PubSub functionality works properly.

         using (var client = new WebsocketClient(url, () =>
         {
             var inner = new ClientWebSocket();
             return inner;
         }))

Summary:
1) If I use the PubSub dashboards "Client URL Generator" to get a URL, the FWebSocketsModule websocket library connects to Azure WebPubSub and works properly

2) If I instead generate the websocket URL using WebPubSubServiceClient::GenerateClientAccessUri() per microsoft samples, the FWebSocketsModule websocket fails with "401 Unauthorized" error.

3) However, that exact same websocket URL works properly when used in a C# program (based on Microsoft samples) and WebsocketClient object.

Anyone have an idea what I'm doing wrong?

Thanks!
-greg





azure-web-pubsub
image.png (35.3 KiB)
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Ok, it appears my failure is linked to specifying the userId string in GenerateClientAccessUri(). If I don't specify a userId, then my URL generated by

      WebPubSubServiceClient::GenerateClientAccessUri()

connects properly when open from

      FWebSocketsModule::Get().CreateWebSocket(PubSubURL, TEXT("json.webpubsub.azure.v1"))

However, if I specify userId,

               WebPubSubServiceClient::GenerateClientAccessUri(userId: "1234");

then the websocket connect Upgrade fails with

               "401 Unauthorized".

Oddly, my C# sample using

               WebsocketClient(url);

to connect does work with a defined userId.

From this, is it safe to assume the Upgrade header from C# WebSocketClient() provides additional header data in the protocol Upgrade request that makes the connect succeed?

Note I tried working through a proxy to try to sniff the wss connection unencrypted (to see what's in the headers), but could not get that to work.

Thanks,
-greg




0 Votes 0 ·

1 Answer

GregTinney-2719 avatar image
1 Vote"
GregTinney-2719 answered GregTinney-2719 commented

Argh, finally found the cause of my WebSocket connect issue.

Basically, it appears that WebPubSub embeds some setup metadata into the derived websocket URL. In particular, adding the userId, even when short, results in 20-30 extra characters in the URL versus when userId is not defined in the call to

      WebPubSubServiceClient::GenerateClientAccessUri()

When I noticed, this I looked at Epic's Unreal 4 Engine source for the wrapper that manages the third-party libwebsockets library. And found this:

  void FLwsWebSocket::ConnectInternal(struct lws_context &LwsContext)
  {
       ...
       **char UrlPath[300];**
       ...

Ugh.

Bad bug on Epic's part there. For a quick test upped that char array to 500 slots and WebPubSub works great, even with userId and session expirations defined. Though the number of roles defined need to be limited or that 500 characters would not cover it.

Need to make that string dynamically sized, and should be good to go!


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.