Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modbux.Tcp.Client terminates when TCP response contains 2 payloads #14

Open
pojiro opened this issue Aug 5, 2024 · 6 comments
Open

Comments

@pojiro
Copy link

pojiro commented Aug 5, 2024

Hi, thanks for your modbus library. I found an issue when I use this library. So I report.

What happens

Modbux.Tcp.Client terminates when TCP response contains 2 payloads.
Following is the log,

07:10:12.450 [error] (Elixir.Modbux.Tcp) size = 5, payload_size = 17, msg = <<0x7, 0x8E, 0x0, 0x0, 0x0, 0x5, 0x0, 0x2, 0x2, 0x1, 0x80, 0x7, 0x8F, 0x0, 0x0, 0x0, 0x6, 0x0, 0x5, 0x0, 0x10, 0xFF, 0x0>>

07:10:12.450 [error] GenServer #PID<0.17883.0> terminating
** (FunctionClauseError) no function clause matching in Modbux.Response.parse/2
    (modbux 0.3.13) lib/helpers/response.ex:64: Modbux.Response.parse({:ri, 0, 0, 16}, nil)
    (modbux 0.3.13) lib/tcp/client.ex:330: Modbux.Tcp.Client.handle_info/2
    (stdlib 6.0) gen_server.erl:2173: :gen_server.try_handle_info/3
    (stdlib 6.0) gen_server.erl:2261: :gen_server.handle_msg/6
    (stdlib 6.0) proc_lib.erl:329: :proc_lib.init_p_do_apply/3
Last message: {:tcp, #Port<0.10199>, <<7, 142, 0, 0, 0, 5, 0, 2, 2, 1, 128, 7, 143, 0, 0, 0, 6, 0, 5, 0, 16, 255, 0>>}
** (EXIT from #PID<0.17850.0>) shell process exited with reason: an exception was raised:
    ** (FunctionClauseError) no function clause matching in Modbux.Response.parse/2
        (modbux 0.3.13) lib/helpers/response.ex:64: Modbux.Response.parse({:ri, 0, 0, 16}, nil)
        (modbux 0.3.13) lib/tcp/client.ex:330: Modbux.Tcp.Client.handle_info/2
        (stdlib 6.0) gen_server.erl:2173: :gen_server.try_handle_info/3
        (stdlib 6.0) gen_server.erl:2261: :gen_server.handle_msg/6
        (stdlib 6.0) proc_lib.erl:329: :proc_lib.init_p_do_apply/3

There are two payloads in the response.

  1. <<0x7, 0x8E, 0x0, 0x0, 0x0, 0x5, 0x0, 0x2, 0x2, 0x1, 0x80>>
  2. <<0x7, 0x8F, 0x0, 0x0, 0x0, 0x6, 0x0, 0x5, 0x0, 0x10, 0xFF, 0x0>>

But following code try to handle this response as one payload, so it fails.

def handle_info({:tcp, _port, response}, state) do


If you need any info, let me know. Thank you!

@alde103
Copy link
Member

alde103 commented Aug 5, 2024

Hi,

Can you confirm (using wireshark or similar) that you are indeed receiving both payloads in the same tcp message?

I think that the problem is the :packet option of :gen_tcp (currently :raw).

@pojiro
Copy link
Author

pojiro commented Aug 6, 2024

Thanks for your quick reply. Currently the machine is located remote. But I will get it.
When I get it, I will capture the log with wireshark and confirm it, then report. Thanks!

@pojiro
Copy link
Author

pojiro commented Aug 9, 2024

I attached the packets log, the_packets.pcapng.zip, that I captured by wireshark.

The issue's log is following, <<0x4, 0x7B>>, <<0x4,0x7C>> corresponds to trans id 1147, 1148.

07:44:03.214 [error] (Elixir.Modbux.Tcp) size = 6, payload_size = 17, msg = <<0x4, 0x7B, 0x0, 0x0, 0x0, 0x6, 0x0, 0x5, 0x0, 0x10, 0x0, 0x0, 0x4, 0x7C, 0x0, 0x0, 0x0, 0x5, 0x0, 0x2, 0x2, 0x0, 0x0>>

07:44:03.215 [error] GenServer #PID<0.1849.0> terminating
** (FunctionClauseError) no function clause matching in Modbux.Response.parse/2
    (modbux 0.3.13) lib/helpers/response.ex:64: Modbux.Response.parse({:fc, 0, 16, 0}, nil)
    (modbux 0.3.13) lib/tcp/client.ex:330: Modbux.Tcp.Client.handle_info/2
    (stdlib 6.0) gen_server.erl:2173: :gen_server.try_handle_info/3
    (stdlib 6.0) gen_server.erl:2261: :gen_server.handle_msg/6
    (stdlib 6.0) proc_lib.erl:329: :proc_lib.init_p_do_apply/3
Last message: {:tcp, #Port<0.69>, <<4, 123, 0, 0, 0, 6, 0, 5, 0, 16, 0, 0, 4, 124, 0, 0, 0, 5, 0, 2, 2, 0, 0>>}

The following capture show the issue packets,

image

This response was from :gen_tcp with active: true, here

def handle_info({:tcp, _port, response}, state) do

then

values = Tcp.parse_res(cmd, response, transid)

finally reached here

def parse_res(cmd, wraped, transid) do

So I guess that :gen_tcp reads several packets together at once.

@alde103
Copy link
Member

alde103 commented Aug 12, 2024

Hi, I create this branch, that expose the packet argument from :gen_tcp, this parameter (packet_format in modbux) accepts 0 | 1 | 2 | 4 | :raw (default: :raw, :raw == 0), however, it seems that the client and the server must match this parameter (https://stackoverflow.com/questions/43957164/erlang-client-server-example-using-gen-tcp-is-not-receiving-anything), so please give it a try, hope this helps.

Example:

# Starts the Client that will connect to a Server with tcp port: 2000
{:ok, cpid} = Modbux.Tcp.Client.start_link(ip: {127,0,0,1}, tcp_port: 2000, timeout: 2000, packet_format: 1)
# Connect to the Server
Modbux.Tcp.Client.connect(cpid)
# Read 1 coil at 20818 from the device 80
Modbux.Tcp.Client.request(cpid, {:rc, 0x50, 20818, 1})
# Parse the Server response
resp = Modbux.Tcp.Client.confirmation(cpid) 
# resp == {:ok, [0]}

@pojiro
Copy link
Author

pojiro commented Aug 12, 2024

Hi, I read the stackoverflow link and the section of the book, Programming Erlang).
I also read https://stackoverflow.com/questions/36854060/using-packet-n-in-gen-tcp-and-how-to-receive-data-in-a-c-program

In my understanding, I cannot use the option for this case. Because the target machine, modbus server, doesn't support the header length which :gen_tcps {:packet, N} option add. I think we use this option when we write :gen_tcp in client and server both with same N.

Thanks.

@pojiro
Copy link
Author

pojiro commented Aug 13, 2024

@alde103 This is not an immediate issue, so it's enough if you took this as a report that I have found such a case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants