BroadbandForum / obuspa

OB-USP-AGENT is a system daemon providing a User Services Platform (USP) Agent. https://github.com/BroadbandForum/obuspa/wiki
BSD 3-Clause "New" or "Revised" License
93 stars 62 forks source link

Problem connecting with python controller #79

Closed jdalmasso1 closed 1 year ago

jdalmasso1 commented 1 year ago

Hi everyone.

I'm trying to connect the OB-USP-Agent to a python controller that is working and listening with WebSockets. The WebSockets Server is in 10.0.2.20:8080, while the OBUSPA is running on another VM in the same LAN (10.0.2.10). Ping between both is OK.

The factory_reset_example.txt is:

#
# The following parameters will definitely need modifying
#

# Controller's websocket server (for agent initiated sessions)
Device.LocalAgent.Controller.1.EndpointID "self::usp-controller.com"
Device.LocalAgent.Controller.1.MTP.1.WebSocket.Host "10.0.2.20"
Device.LocalAgent.Controller.1.MTP.1.WebSocket.Port "8080"
Device.LocalAgent.Controller.1.MTP.1.WebSocket.Path "/usp"
Device.LocalAgent.Controller.1.MTP.1.WebSocket.EnableEncryption "false"

# Agent's websocket server (for controller initiated sessions)
Device.LocalAgent.MTP.1.WebSocket.Port "3000"
Device.LocalAgent.MTP.1.WebSocket.Path "/usp"
Device.LocalAgent.MTP.1.WebSocket.EnableEncryption "false"

#
# The following parameters may be modified
#
Device.LocalAgent.MTP.1.Alias "cpe-1"
Device.LocalAgent.MTP.1.Enable "true"
Device.LocalAgent.MTP.1.Protocol "WebSocket"
Device.LocalAgent.MTP.1.WebSocket.KeepAliveInterval "30"
Device.LocalAgent.Controller.1.Alias "cpe-1"
Device.LocalAgent.Controller.1.Enable "true"
Device.LocalAgent.Controller.1.AssignedRole "Device.LocalAgent.ControllerTrust.Role.1"
Device.LocalAgent.Controller.1.PeriodicNotifInterval "60"
Device.LocalAgent.Controller.1.PeriodicNotifTime "0001-01-01T00:00:00Z"
Device.LocalAgent.Controller.1.USPNotifRetryMinimumWaitInterval "5"
Device.LocalAgent.Controller.1.USPNotifRetryIntervalMultiplier "2000"
Device.LocalAgent.Controller.1.ControllerCode ""
Device.LocalAgent.Controller.1.MTP.1.Alias "cpe-1"
Device.LocalAgent.Controller.1.MTP.1.Enable "true"
Device.LocalAgent.Controller.1.MTP.1.Protocol "WebSocket"
Device.LocalAgent.Controller.1.MTP.1.WebSocket.KeepAliveInterval "30"
Device.LocalAgent.Controller.1.MTP.1.WebSocket.SessionRetryMinimumWaitInterval "5"
Device.LocalAgent.Controller.1.MTP.1.WebSocket.SessionRetryIntervalMultiplier "2000"
Internal.Reboot.Cause "LocalFactoryReset"

The error on the agent side is:

Attempting to connect to host=10.0.2.20 (port=8080, unencrypted, path=/usp) from interface=enp0s3
HandleWscEvent_Error: Error (HS: ws upgrade response not 101) occurred on websocket connection to endpoint_id=self::usp-controller.com (host=10.0.2.20)
HandleWscEvent_Destroyed: Closed connection to self::usp-controller.com
ScheduleWsclientRetry: Retrying connection in 49 seconds (retry_count=4)

When capturing with Wireshark, I see this:

GET /usp HTTP/1.1
Pragma: no-cache
Cache-Control: no-cache
Host: 10.0.2.20
Origin: http://10.0.2.20
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: YknuJlHhf/SEXtayfJ4vQA==
Sec-WebSocket-Protocol: v1.usp
Sec-WebSocket-Version: 13
sec-websocket-extensions: bbf-usp-protocol; eid="os::012345-0800272529AB"

HTTP/1.1 400 Bad Request
Date: Wed, 19 Apr 2023 17:46:20 GMT
Server: Python/3.8 websockets/11.0.2
Content-Length: 156
Content-Type: text/plain
Connection: close

Failed to open a WebSocket connection: invalid Sec-WebSocket-Extensions header: invalid quoted header content at 22 in bbf-usp-protocol; eid="os::012345-0800272529AB".

Can you help with this issue?

jdalmasso1 commented 1 year ago

The controller python code is:

import asyncio
import websockets
import usp_example_pb2

async def handle_message(websocket, path):
    async for data in websocket:
        # Parse the incoming message
        msg = usp_pb2.Message()
        msg.ParseFromString(data)
        # Check if the message is a Get request
        if msg.header.msg_type == usp_pb2.Header.GET:
            # Process the Get request
            get_resp = usp_pb2.Message()
            get_resp.header.msg_id = msg.header.msg_id
            get_resp.header.msg_type = usp_pb2.Header.GET_RESP
            get_resp.header.msg_version = "1.0"
            get_resp.header.encryption_mode = usp_pb2.Header.PLAINTEXT
            get_resp.body.response.get_resp.value = "Hello, world!"
            await websocket.send(get_resp.SerializeToString())

start_server = websockets.serve(handle_message, "10.0.2.20", 8080)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

The library usp_example_pb2 is generated by protoc the following file:

// usp_example.proto
syntax = "proto3";
message DeviceInfoRequest {
  string token = 1;
}
message DeviceInfoResponse {
  string device_id = 1;
  string firmware_version = 2;
  string model = 3;
}
holme-r commented 1 year ago

It looks like the python library does not like the Sec-WebSocket-Extensions header ("invalid quoted header content") and most likely this is because it is requiring the string to be escaped. But in the forthcoming USP 1.3 specification, the requirement for the client to send the Sec-WebSocket-Extensions header is being deprecated anyway, so I think the simplest fix is to comment out the call to AddWsclientUspExtension() in wsclient.c, so that OBUSPA doesn't send the Sec-WebSocket-Extensions header. Please try this. We will be updating OBUSPA to USP 1.3 after it is released, removing the Sec-WebSocket-Extensions header officially from the OBUSPA codebase.

holme-r commented 1 year ago

Closing as this appears to have addressed the issue. Please re-open if there are still issues.