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

support SO_REUSEPORT socket option #108

Closed
prjemian opened this issue Apr 18, 2020 · 33 comments
Closed

support SO_REUSEPORT socket option #108

prjemian opened this issue Apr 18, 2020 · 33 comments

Comments

@prjemian
Copy link

The SO_REUSEPORT socket option allows multiple clients on the same user@host to bind to the same UDP port. With this option enabled in asyn, I expect to be able to run multiple IOCs using new support for the Oxford CS800 CryoStream controller (blows cold nitrogen gas at protein sample during crystallography measurement). Currently, when I try to run a second IOC from the same user@host, this error is reported to the console and no communications is the result:

# ### cs800.iocsh ###
# STATUS_ADDR  "255.255.255.255:30304:30304 UDP"
# COMMAND_ADDR "10.0.0.173:30305 UDP*"
# Status Packets
drvAsynIPPortConfigure("OC_SP", "192.168.144.169:30304:30304 UDP*", 0, 0, 0)
2020/04/18 11:16:04.544 OC_SP -1 autoConnect could not connect: unable to bind to local port: Address already in use
# Commands

Is it possible to call setsockopt() (similar to what is shown) from the st.cmd file?

Otherwise, can support for the SO_REUSEPORT socket option be enabled in asyn? The text SO_REUSEPORT does not appear anywhere in the asyn repo so I assume this option is not available yet.

@prjemian
Copy link
Author

Without this option, I must run each instance of this support on a separate workstation (or using a separate NIC if multiple NICs are available on the same workstation).

@prjemian
Copy link
Author

Stackoverflow has some entries about SO_REUSEPORT.

My goal is to run multiple IOCs on the same host from same username, each supporting a different CS800 controller. Advice is welcome.

@norumwe12
Copy link
Contributor

norumwe12 commented Apr 18, 2020 via email

@ralphlange
Copy link
Member

I don't think this is going to work.

If the devices are sending UDP data to the same port on the IOC host (as the protocol file suggests), only the last IOC that was started will get all data. (Unless the devices are sending broadcasts. Then all IOCs will get all data. That's technically the same issue as with Channel Access name resolution not working properly on a Linux box running multiple IOCs if the client uses unicasts.)

Have a look at how to configure virtual network interfaces on your host - which is actually pretty simple on Linux. Then every IOC can use its own IP address for the device connection and all is good.

@prjemian
Copy link
Author

+1 for virtual NICs, thanks.

The CS800 controllers broadcast status once a second by UDP to port 30304. Another problem to resolve is all status broadcasts being received by every IOC. That seems to be be resolved by specifying the IP number of the controller:

epicsEnvSet("CS800_IP_ADDR", "10.0.0.173")
epicsEnvSet("STATUS_ADDR", "$(CS800_IP_ADDR):30304:30304 UDP")
epicsEnvSet("COMMAND_ADDR", "$(CS800_IP_ADDR):30305 UDP")
iocshLoad("$(IP)ipApp/Db/Oxford_CS800.iocsh", "PREFIX=$(PREFIX),INSTANCE=CS")

At least it works when I start an IOC and two simulated CS800 controllers on the same subnet. I can test with real controllers on Monday when the beam is down.

@prjemian
Copy link
Author

The iocshLoad calls this code:

# STATUS_ADDR  "255.255.255.255:30304:30304 UDP"
# COMMAND_ADDR "10.0.0.173:30305 UDP*"

# Status Packets
drvAsynIPPortConfigure("OC_SP", "$(STATUS_ADDR)", 0, 0, 0)
# Commands
drvAsynIPPortConfigure("OC_CMD", "$(COMMAND_ADDR)", 0, 0, 0)

@ralphlange
Copy link
Member

Then a reused port is the same as multiple virtual NICs.
Can't you just run them all from one IOC? Doesn't look like too much traffic, and you probably don't have hundreds of them, either.

@prjemian
Copy link
Author

Trying it but it fails.

# ### cs800.iocsh ###
# STATUS_ADDR  "255.255.255.255:30304:30304 UDP"
# COMMAND_ADDR "10.0.0.173:30305 UDP*"
# Status Packets
drvAsynIPPortConfigure("OC_SP", "192.168.144.144:30304:30304 UDP", 0, 0, 0)
# Commands
drvAsynIPPortConfigure("OC_CMD", "192.168.144.144:30305 UDP", 0, 0, 0)
#asynSetTraceIOMask("OC_SP", 0, 2)
#asynSetTraceMask("OC_SP", 0, 9)
#asynSetTraceIOMask("OC_CMD", 0, 2)
#asynSetTraceMask("OC_CMD", 0, 9)
dbLoadRecords("/usr/local/epics/synApps_6_1/support/asyn-R4-37/db/asynRecord.db","P=cs800:,R=CS:ASYN:SP,PORT=OC_SP,ADDR=0,OMAX=1000,IMAX=1000")
dbLoadRecords("/usr/local/epics/synApps_6_1/support/asyn-R4-37/db/asynRecord.db","P=cs800:,R=CS:ASYN:CMD,PORT=OC_CMD,ADDR=0,OMAX=1000,IMAX=1000")
epicsEnvSet("STREAM_PROTOCOL_PATH", ".:/usr/local/epics/synApps_6_1/support/ip-git/ipApp/Db")
dbLoadRecords("/usr/local/epics/synApps_6_1/support/ip-git/db/Oxford_CS800.db", "P=cs800:,Q=CS,PORT=OC_SP,PORTCMD=OC_CMD")
drvAsynIPPortConfigure("OC_SP2", "192.168.144.169:30304:30304 UDP", 0, 0, 0)
2020/04/18 14:54:59.262 OC_SP2 -1 autoConnect could not connect: unable to bind to local port: Address already in use
drvAsynIPPortConfigure("OC_CMD2", "192.168.144.169:30305 UDP", 0, 0, 0)

Changing :30304:30304 to :30304 starts with no errors. But no PV updates (from streams support).

@prjemian
Copy link
Author

Summary is that any and all status broadcasts will come in to asyn configured:

drvAsynIPPortConfigure("OC_SP", "255.255.255.255:30304:30304 UDP", 0, 0, 0)

which moves the problem a little further along to stream: how to separate the status broadcasts by their sender? The IP and MAC addresses of the sender are in the packet header and the IP address is also in the packet data. A C or SNL program could filter out the status from the desired controller but filtering by IP sender that is probably beyond the capability of a stream protocol.

@ralphlange
Copy link
Member

Ok. When you want to filter by sender address by configuring UDP "connections", you need a separate for each - then we need the SO_REUSEPORT again.
Trying to have Stream split the messages apart? Sounds complex. Probably needs a separate protocol for each device so that Stream can match the right one. Or some database plumbing where Stream puts the data and the IP address in shared records and fires a bunch of calcout/seq combinations that forward the data to the right target records if the IP matches.

SO_REUSEPORT or virtual NICs sound like a more obvious approach.

@prjemian
Copy link
Author

I agree. How hard is it to add?

@prjemian
Copy link
Author

And for now, support each CS800 controller from a separate host.

@ralphlange
Copy link
Member

virtual NICs should work for now.

@prjemian
Copy link
Author

That's much easier on the home LAN than the working beam line. They are very risk averse since they can do virus-related work now.

@prjemian
Copy link
Author

Thanks for all the help!

@ralphlange
Copy link
Member

As Eric mentioned: the change itself is not too hard to do. A single call on the socket. Windows portability has been solved for the Channel Access case (in the UDP server).

Question is if Mark wants to keep the sockets single-use by default (which might make sense) and - if so - which would be the appropriate way to configure the REUSEPORT option.

Welcome!

@ralphlange
Copy link
Member

One message from Eric does not show up here - I just got the mail, don't know what happened:

The driver does a connect() so I would think that packets from the hosts in question would be delivered to the correct sockets even if the local address/port is shared. As far as I understand things, a socket is associated with 5 attributes, namely a protocol, source address, source port, destination address, destination port, so the network stack has enough information for packets to be delivered to the right socket.
e.g.
Socket Protocol Dest Addr Dest Port Source Addr Source Port
1 UDP Host A Port A My IP address Shared Port
2 UDP Host B Port B My IP address Shared Port

So incoming packets from Host A, Port A would be delivered to socket 1 and those from Host B, Port B, would be delivered to socket 2, right?
Or is this one of those corner cases that a significant number (all?) kernels get wrong?

@ralphlange
Copy link
Member

Well, I always thought that connect() on a UDP socket only stores the default peer data, so that the application can use send() and recv() instead of the fully specified _from() versions of the calls. (And be more efficient, as routing does not have to be checked for every send/recv call.)

I do agree that the kernel should have all necessary information to get the routing right. I never worked with such a UDP "connection", so I can't say if this setup falls under the UDP server case where all non-broadcast packages get delivered to exactly one process waiting on the shared port.

Nevertheless: I don't think adding the SO_REUSEPORT specifically for the local port of a UDP client "connection" setup would change behavior that existing applications rely on. (So, no need to introduce an option to the user visible API.)

@MarkRivers
Copy link
Member

Questions:

  • Does SO_REUSEPORT only make sense for UDP, or might it be useful for TCP as well?
  • For UDP does it only make sense if broadcast is also enabled as in Pete's example?

I can think of 2 ways to handle the API.

  1. Introduce a new character in the protocol that means SO_REUSEPORT, for example &. Then depending on the answers to the above questions new protocols would be
  • udp&
  • udp*&
  • tcp&
  1. Use the asynOption interface, like the following.
# Create the port with autoconnect=0.
drvAsynIPPortConfigure("OC_SP", "192.168.144.169:30304:30304 UDP*", 0, 1, 0)
# Enable SO_REUSEPORT
asynSetOption("OC_SP", 0,  "SO_REUSEPORT", "Y")
# Now enable autoconnect
asynAutoConnect("OC_SP", 0,  1)

I will work on this once I hear a consensus on which variations make sense.

@MarkRivers
Copy link
Member

Sorry, I just noticed Ralph's comment:

Nevertheless: I don't think adding the SO_REUSEPORT specifically for the local port of a UDP client "connection" setup would change behavior that existing applications rely on. (So, no need to introduce an option to the user visible API.)

However, this article explains the uses of SO_REUSEPORT, and how it can be useful for both TCP and UDP.

https://lwn.net/Articles/542629/

But for TCP I don't think we want to make it the default, so we do need an API change to handle it.

@MarkRivers
Copy link
Member

I have created a new branch of asyn, SO_REUSEPORT. It implements option 1) above, i.e. new protocols:

  • udp&
  • udp*&
  • tcp&

On _WIN32 I used the socket option SO_REUSEADDR because SO_REUSEPORT is not supported. This article says that it does what Pete wants for UDP broadcast sockets:
https://stackoverflow.com/questions/13637121/so-reuseport-is-not-defined-on-windows-7

On all other architectures it uses the socket option SO_REUSEPORT.

I have tested that it compiles on Linux, vxWorks, and Windows VS2015.

@prjemian can you see if it works for you on Linux?

@prjemian
Copy link
Author

Thanks for the quick response. I'll get to it later today. Faster if the weather goes bad but that's not likely. If this works, this can save me from a rewrite of the CS800 support in SNL.

@norumwe12
Copy link
Contributor

norumwe12 commented Apr 19, 2020 via email

@ralphlange
Copy link
Member

Thanks a lot, Mark. The change looks good.

This will allow adding the SO_REUSEPORT flag for all client type configurations, so that the originating port of the connection can be shared. Server type ports are still exclusive. IMHO this is ok (as it would directly lead to the issue with incoming broadcasts vs. unicasts) and we can relax and wait for someone to actually need that feature. Just wanted to make it clear.

@prjemian
Copy link
Author

prjemian commented Apr 20, 2020

Working with two CS800 simulators:

PREFIX IP controller ID
cs800: 192.168.144.144 144
cryo: 192.168.144.113 113

UDP*&

Starting support for both from the same linux-x86_64 soft IOC (running on 192.168.144.99) using UDP*& for both status and command ports:

st.cmd configuration
# ----------------------------------------------------------
# >>> first CS800 ----------------
# Oxford CryoStream 800 cooler
epicsEnvSet("CS800_IP_ADDR", "192.168.144.144")
epicsEnvSet("STATUS_ADDR", "$(CS800_IP_ADDR):30304:30304 UDP*&")
epicsEnvSet("COMMAND_ADDR", "$(CS800_IP_ADDR):30305 UDP*&")
iocshLoad("$(IP)/iocsh/Oxford_CS800.iocsh", "PREFIX=$(PREFIX),INSTANCE=CS")
# <<< first CS800 ----------------
# ----------------------------------------------------------


# ----------------------------------------------------------
# >>> second CS800 ----------------
epicsEnvSet("CS800_IP_ADDR2", "192.168.144.113")
drvAsynIPPortConfigure("CS800_STATUS", "${CS800_IP_ADDR2}:30304:30304 UDP*&", 0, 0, 0)
drvAsynIPPortConfigure("CS800_COMMAND", "${CS800_IP_ADDR2}:30305 UDP*&", 0, 0, 0)

dbLoadRecords("/usr/local/epics/synApps_6_1/support/asyn-git/db/asynRecord.db","P=cryo:,R=CS:ASYN:SP,PORT=CS800_STATUS,ADDR=0,OMAX=1000,IMAX=1000")
dbLoadRecords("/usr/local/epics/synApps_6_1/support/asyn-git/db/asynRecord.db","P=cryo:,R=CS:ASYN:CMD,PORT=CS800_COMMAND,ADDR=0,OMAX=1000,IMAX=1000")
# epicsEnvSet("STREAM_PROTOCOL_PATH", ".:/usr/local/epics/synApps_6_1/support/ip-git/ipApp/Db")
dbLoadRecords("/usr/local/epics/synApps_6_1/support/ip-git/db/Oxford_CS800.db", "P=cryo:,Q=CS,PORT=CS800_STATUS,PORTCMD=CS800_COMMAND")
# <<< second CS800 ----------------
# ----------------------------------------------------------

No errors on startup:

IOC console output on startup
# ----------------------------------------------------------
# >>> first CS800 ----------------
# Oxford CryoStream 800 cooler
epicsEnvSet("CS800_IP_ADDR", "192.168.144.144")
epicsEnvSet("STATUS_ADDR", "192.168.144.144:30304:30304 UDP*&")
epicsEnvSet("COMMAND_ADDR", "192.168.144.144:30305 UDP*&")
iocshLoad("/usr/local/epics/synApps_6_1/support/ip-git/iocsh/Oxford_CS800.iocsh", "PREFIX=cs800:,INSTANCE=CS")
# ### cs800.iocsh ###
# STATUS_ADDR  "255.255.255.255:30304:30304 UDP"
# COMMAND_ADDR "10.0.0.173:30305 UDP*"
# Status Packets
drvAsynIPPortConfigure("OC_SP", "192.168.144.144:30304:30304 UDP*&", 0, 0, 0)
# Commands
drvAsynIPPortConfigure("OC_CMD", "192.168.144.144:30305 UDP*&", 0, 0, 0)
#asynSetTraceIOMask("OC_SP", 0, 2)
#asynSetTraceMask("OC_SP", 0, 9)
#asynSetTraceIOMask("OC_CMD", 0, 2)
#asynSetTraceMask("OC_CMD", 0, 9)
dbLoadRecords("/usr/local/epics/synApps_6_1/support/asyn-git/db/asynRecord.db","P=cs800:,R=CS:ASYN:SP,PORT=OC_SP,ADDR=0,OMAX=1000,IMAX=1000")
dbLoadRecords("/usr/local/epics/synApps_6_1/support/asyn-git/db/asynRecord.db","P=cs800:,R=CS:ASYN:CMD,PORT=OC_CMD,ADDR=0,OMAX=1000,IMAX=1000")
epicsEnvSet("STREAM_PROTOCOL_PATH", ".:/usr/local/epics/synApps_6_1/support/ip-git/ipApp/Db")
dbLoadRecords("/usr/local/epics/synApps_6_1/support/ip-git/db/Oxford_CS800.db", "P=cs800:,Q=CS,PORT=OC_SP,PORTCMD=OC_CMD")
# <<< first CS800 ----------------
# ----------------------------------------------------------
# ----------------------------------------------------------
# >>> second CS800 ----------------
epicsEnvSet("CS800_IP_ADDR2", "192.168.144.113")
drvAsynIPPortConfigure("CS800_STATUS", "192.168.144.113:30304:30304 UDP*&", 0, 0, 0)
drvAsynIPPortConfigure("CS800_COMMAND", "192.168.144.113:30305 UDP*&", 0, 0, 0)
dbLoadRecords("/usr/local/epics/synApps_6_1/support/asyn-git/db/asynRecord.db","P=cryo:,R=CS:ASYN:SP,PORT=CS800_STATUS,ADDR=0,OMAX=1000,IMAX=1000")
dbLoadRecords("/usr/local/epics/synApps_6_1/support/asyn-git/db/asynRecord.db","P=cryo:,R=CS:ASYN:CMD,PORT=CS800_COMMAND,ADDR=0,OMAX=1000,IMAX=1000")
# epicsEnvSet("STREAM_PROTOCOL_PATH", ".:/usr/local/epics/synApps_6_1/support/ip-git/ipApp/Db")
dbLoadRecords("/usr/local/epics/synApps_6_1/support/ip-git/db/Oxford_CS800.db", "P=cryo:,Q=CS,PORT=CS800_STATUS,PORTCMD=CS800_COMMAND")
# <<< second CS800 ----------------
# ----------------------------------------------------------

Watching for the controller ID for each instance. Both EPICS database instances receive status updates from both controllers (this is not correct).

pi@ambodeh:~/.../cs800sim/v1 $ camonitor {cs800,cryo}:CS:CTRLNUM
cs800:CS:CTRLNUM               2020-04-20 11:52:34.557478 113
cryo:CS:CTRLNUM                2020-04-20 11:52:34.557476 113
cryo:CS:CTRLNUM                2020-04-20 11:52:35.126938 144
cs800:CS:CTRLNUM               2020-04-20 11:52:35.126937 144
cs800:CS:CTRLNUM               2020-04-20 11:52:35.560535 113
cryo:CS:CTRLNUM                2020-04-20 11:52:35.560537 113
cryo:CS:CTRLNUM                2020-04-20 11:52:36.144231 144
cs800:CS:CTRLNUM               2020-04-20 11:52:36.144232 144
cs800:CS:CTRLNUM               2020-04-20 11:52:36.563610 113
cryo:CS:CTRLNUM                2020-04-20 11:52:36.563614 113
cryo:CS:CTRLNUM                2020-04-20 11:52:37.156794 144
cs800:CS:CTRLNUM               2020-04-20 11:52:37.156795 144
cryo:CS:CTRLNUM                2020-04-20 11:52:37.566597 113
cs800:CS:CTRLNUM               2020-04-20 11:52:37.566650 113
cs800:CS:CTRLNUM               2020-04-20 11:52:38.187451 144
cryo:CS:CTRLNUM                2020-04-20 11:52:38.187454 144
cryo:CS:CTRLNUM                2020-04-20 11:52:38.569569 113
cs800:CS:CTRLNUM               2020-04-20 11:52:38.569570 113
^C

Verified that command sent from EPICS PV to one controller is only received by the correct controller. For both controllers. (this is correct)

UDP&

Changing to UDP& (remove the broadcast configuration) and same results for status and commands. That is, each database receives all status updates (this is not correct). Commands sent to intended controller (this is correct).

:30304:30304 vs. :30304

When this part is shortened from :30304:30304 to :30304, no status updates are received by either controller.

How can this be configured so that status updates from controller 144 are received only by the EPICS database for that controller?

@norumwe12
Copy link
Contributor

norumwe12 commented Apr 20, 2020 via email

@MarkRivers
Copy link
Member

@prjemian I think the simplest configuration is to use UDP& on the status port and UDP on the command port. I don't think there is a need for the broadcast flag on the status port. The broadcast flag is to allow EPICS to send broadcasts, nothing special needs to be done to receive them. The command port does not need the & flag, it is just a normal UDP port.

How can this be configured so that status updates from controller 144 are received only by the EPICS database for that controller?

Fix the network stack?
Place the devices on different virtual NICs?
Tell the manufacturer to use a less bizarre communications method?

@prjemian can you send the asynTrace output on the status port with asynSetTraceMask=TRACE_ERROR|TRACEIO_DRIVER so we can see the message content? I think you said in a previous message that the status message contains the IP address of the machine sending the message? If so then I think I can add to @norumwe12's list above:

  • Write an asynInterpose layer. This will be configured with the IP address of the desired sender. It will discard messages that are not from that IP address. That way you will only receive messages from the desired IP address.

@prjemian
Copy link
Author

@norumwe12 said:

Fix the network stack?

I'm developing on a linux mint OS with most recent updates for deployment on RHEL7 at the APS. Might bear to test on the APS network before proceeding with this.

Place the devices on different virtual NICs?

already responded to this

Tell the manufacturer to use a less bizarre communications method?

possible

@prjemian
Copy link
Author

prjemian commented Apr 20, 2020

@MarkRivers : the IP address is in the UDP packet header. Can the asynRecord access that content?

Here's a few packets with asynSetTraceMask=TRACE_ERROR|TRACEIO_DRIVER:

ioccs800> 2020/04/20 14:22:42.131 192.168.144.144:30304:30304 UDP& (from 192.168.144.113:55932) read 928

2020/04/20 14:22:42.888 192.168.144.144:30304:30304 UDP& (from 192.168.144.144:47912) read 928

2020/04/20 14:22:43.131 192.168.144.144:30304:30304 UDP& (from 192.168.144.113:55932) read 928

2020/04/20 14:22:43.898 192.168.144.144:30304:30304 UDP& (from 192.168.144.144:47912) read 928

2020/04/20 14:22:44.131 192.168.144.144:30304:30304 UDP& (from 192.168.144.113:55932) read 928

repeating that with traceIOHex ON:

ioccs800> 
ioccs800> 2020/04/20 14:23:27.235 192.168.144.144:30304:30304 UDP& (from 192.168.144.113:55932) read 928

aa ab 03 98 03 e8 01 df 03 e9 01 b4 03 ea 39 f3 03 eb 37 a0 
03 ec 04 4f 03 ed 02 18 03 ee 02 27 03 f2 01 de 03 f3 02 19 
03 f4 00 20 03 f5 00 20 03 f6 01 ce 03 f7 01 cb 03 f8 01 de 
03 f9 02 17 03 fa 00 22 03 fb 02 22 03 fc 01 bf 03 fd 01 8d 
03 fe 02 08 03 ff 01 9d 04 00 01 ba 04 01 01 e2 04 02 01 b5 
04 03 01 f6 04 04 00 71 04 05 0c a4 04 06 0d 15 04 07 01 cb 
04 08 01 f7 04 09 01 9c 04 0a 02 4e 04 0b 02 1f 04 0c 01 e7 
04 0d 01 fc 04 10 02 1a 04 11 01 fb 04 12 01 cf 04 13 01 f6 
04 14 02 0e 04 15 02 3c 04 16 01 d0 04 1a 27 10 04 1b 27 1d 
04 1c 01 f5 04 1d 00 03 04 1e 00 03 04 1f 01 68 04 20 27 10 
04 21 38 f2 04 22 3d c2 04 23 04 23 04 24 00 11 04 25 00 1d 
04 26 00 1e 04 27 00 20 04 28 02 0a 04 29 01 d4 04 2a 00 03 
04 2b 02 36 04 2c 01 bc 04 2d 00 24 04 2e 00 19 04 2f 01 f0 
04 30 01 ff 04 31 01 ce 04 38 01 e8 04 39 02 0b 04 3a 02 00 
04 3b 01 d8 04 3c 01 f7 04 3d 01 e7 04 3e 01 b0 04 3f 01 9f 
04 40 00 1c 04 41 00 1c 04 42 00 25 04 43 01 e4 04 44 02 06 
04 45 01 ea 04 46 02 18 04 47 02 06 04 48 01 e8 04 49 01 f3 
04 4a 01 f1 04 4c 02 3d 04 4d 00 3a 04 4e 01 a6 04 4f 00 21 
04 50 01 f9 04 51 01 fc 04 52 01 ee 04 53 01 fe 04 54 01 f0 
04 b0 01 c7 04 b1 01 da 04 b2 01 fe 04 b3 00 1b 04 b4 02 13 
04 b5 02 41 04 b6 01 da 04 b7 02 59 04 b8 02 51 04 b9 01 f2 
04 ba 01 f9 04 bb 01 fd 04 bc 02 06 05 14 02 0d 05 15 01 a7 
05 16 01 f7 05 17 01 9a 05 18 01 ed 05 19 01 f6 05 1a 02 1e 
05 1b 02 03 05 1c 01 f7 05 1d 02 18 05 1e 02 35 05 1f 02 1b 
05 20 01 d6 05 21 02 07 05 22 01 da 05 78 01 9c 05 79 02 2c 
05 7a 01 f0 05 7b 01 db 05 7c 02 12 05 7d 01 b6 05 7e 01 b6 
05 7f 01 e0 05 80 02 3a 05 81 01 fc 05 82 01 d1 05 83 02 08 
05 84 01 f1 05 85 02 32 05 86 02 05 05 87 01 c9 05 88 02 05 
05 89 01 ee 05 8a 02 4e 05 8b 01 fb 05 8c 01 c5 05 8d 02 3a 
05 8e 01 db 05 8f 01 d0 05 90 01 f0 05 91 01 fa 05 92 01 9d 
05 93 01 c8 05 94 01 fe 05 95 01 cb 05 96 01 e5 05 97 01 c8 
05 98 01 fb 05 99 01 eb 05 dc 02 0c 05 dd 02 0f 05 de 02 38 
05 df 02 09 05 e0 01 e3 05 e1 01 fe 05 e2 01 b4 05 e3 02 00 
05 e4 02 38 05 e5 01 e8 05 e6 01 d1 05 e7 02 08 05 e8 02 20 
05 e9 01 e6 05 ea 01 e0 05 eb 01 ba 06 40 02 23 06 41 02 49 
06 42 02 0e 06 43 01 f9 06 44 02 06 06 45 01 ec 06 46 01 e4 
06 a4 01 da 06 a5 02 01 07 08 01 f7 07 09 01 f8 07 0a 01 91 
07 0b 01 e5 07 0c 02 12 07 0d 01 e6 07 0e 02 2c 07 0f 01 fe 
07 10 02 23 07 11 01 da 07 12 01 f3 07 13 02 2e 07 14 01 a3 
07 15 02 46 07 6c 01 b2 07 6d 01 d7 07 6e 01 9d 07 6f 01 ae 
07 d0 01 c6 07 d1 01 dc 07 d2 01 f4 07 da 3c 99 07 db 3c 5d 
07 dc 02 01 07 dd 3d db 07 de 00 22 07 df 00 22 07 e0 00 1a 
07 e1 00 15 07 e2 01 9b 07 e3 00 1e 07 e4 00 1f 07 e5 02 10 
07 e6 01 f4 07 e7 01 be 07 e8 01 e5 07 ee 39 87 07 ef 39 73 
07 f0 02 15 07 f1 01 9e 07 f2 01 f6 07 f3 37 f6 07 f4 3c dc 
07 f5 01 c3 07 f6 01 b9 07 f7 01 d8 07 f8 02 01 07 f9 3b 7a 
07 fa 01 e0 f2 0f ab aa 
2020/04/20 14:23:27.631 192.168.144.144:30304:30304 UDP& (from 192.168.144.144:47912) read 928

aa ab 03 98 03 e8 01 9e 03 e9 01 ff 03 ea 3a c2 03 eb 35 0a 
03 ec 04 53 03 ed 01 e9 03 ee 01 cf 03 f2 01 e0 03 f3 01 f2 
03 f4 00 1c 03 f5 00 23 03 f6 02 47 03 f7 01 fe 03 f8 01 cd 
03 f9 01 cf 03 fa 00 26 03 fb 01 cf 03 fc 01 ef 03 fd 01 8c 
03 fe 02 1a 03 ff 01 ce 04 00 01 f5 04 01 01 e6 04 02 01 cf 
04 03 02 33 04 04 00 90 04 05 0c ac 04 06 0d 04 04 07 01 e4 
04 08 01 e2 04 09 02 03 04 0a 01 ec 04 0b 02 19 04 0c 01 93 
04 0d 02 26 04 10 01 eb 04 11 01 9a 04 12 01 df 04 13 01 ab 
04 14 02 1e 04 15 02 06 04 16 02 18 04 1a 27 10 04 1b 27 3f 
04 1c 02 0c 04 1d 00 03 04 1e 00 03 04 1f 01 68 04 20 27 10 
04 21 38 fa 04 22 3c 46 04 23 00 00 04 24 00 14 04 25 00 21 
04 26 00 17 04 27 00 1d 04 28 02 08 04 29 01 c7 04 2a 00 97 
04 2b 01 da 04 2c 01 9e 04 2d 00 19 04 2e 00 13 04 2f 01 f3 
04 30 02 21 04 31 02 06 04 38 02 05 04 39 01 ee 04 3a 01 a3 
04 3b 01 f7 04 3c 02 08 04 3d 02 04 04 3e 02 0f 04 3f 02 49 
04 40 00 12 04 41 00 20 04 42 00 22 04 43 01 ec 04 44 01 fc 
04 45 02 0e 04 46 02 12 04 47 02 02 04 48 01 d6 04 49 01 fe 
04 4a 01 9a 04 4c 02 2f 04 4d 00 42 04 4e 01 ba 04 4f 00 21 
04 50 01 ac 04 51 01 f7 04 52 02 26 04 53 02 1b 04 54 01 f5 
04 b0 01 ce 04 b1 01 f7 04 b2 02 46 04 b3 00 27 04 b4 01 9f 
04 b5 02 43 04 b6 02 42 04 b7 01 de 04 b8 02 03 04 b9 02 52 
04 ba 01 ee 04 bb 02 28 04 bc 02 2c 05 14 01 f5 05 15 01 84 
05 16 02 16 05 17 01 d9 05 18 01 e4 05 19 02 31 05 1a 02 36 
05 1b 01 da 05 1c 01 a9 05 1d 01 c0 05 1e 02 55 05 1f 02 14 
05 20 02 38 05 21 01 df 05 22 01 a0 05 78 01 d3 05 79 01 d4 
05 7a 01 dd 05 7b 02 20 05 7c 01 b9 05 7d 01 f5 05 7e 02 37 
05 7f 01 ef 05 80 01 ef 05 81 01 c9 05 82 01 ca 05 83 02 a3 
05 84 01 e8 05 85 02 09 05 86 02 19 05 87 01 d6 05 88 01 e6 
05 89 01 f5 05 8a 02 36 05 8b 02 1d 05 8c 01 bf 05 8d 02 14 
05 8e 01 bd 05 8f 02 0d 05 90 01 f3 05 91 02 5e 05 92 02 5e 
05 93 01 f7 05 94 02 00 05 95 01 d2 05 96 02 09 05 97 01 e9 
05 98 01 99 05 99 01 9e 05 dc 02 12 05 dd 01 d5 05 de 01 da 
05 df 01 78 05 e0 01 ef 05 e1 01 d2 05 e2 01 e0 05 e3 01 be 
05 e4 02 19 05 e5 02 01 05 e6 01 f1 05 e7 01 f3 05 e8 02 59 
05 e9 02 15 05 ea 02 5d 05 eb 01 ff 06 40 02 0d 06 41 02 1a 
06 42 02 29 06 43 02 26 06 44 02 28 06 45 01 91 06 46 01 ff 
06 a4 01 a9 06 a5 01 96 07 08 01 f7 07 09 02 22 07 0a 01 ae 
07 0b 01 fc 07 0c 02 0e 07 0d 01 fc 07 0e 02 10 07 0f 02 1a 
07 10 02 64 07 11 01 f9 07 12 01 d8 07 13 01 c7 07 14 02 1a 
07 15 02 23 07 6c 01 da 07 6d 01 f8 07 6e 01 ee 07 6f 01 e2 
07 d0 02 04 07 d1 02 27 07 d2 02 23 07 da 37 85 07 db 37 bc 
07 dc 02 3c 07 dd 3e 80 07 de 00 1f 07 df 00 1a 07 e0 00 1e 
07 e1 00 26 07 e2 01 fe 07 e3 00 20 07 e4 00 24 07 e5 01 ef 
07 e6 02 1f 07 e7 01 fd 07 e8 01 d0 07 ee 3a 48 07 ef 3c cb 
07 f0 01 ad 07 f1 01 a1 07 f2 01 e3 07 f3 3b e6 07 f4 39 b9 
07 f5 01 e9 07 f6 02 58 07 f7 01 d3 07 f8 02 1f 07 f9 3f 58 
07 fa 02 3b e7 c1 ab aa 
2020/04/20 14:23:28.238 192.168.144.144:30304:30304 UDP& (from 192.168.144.113:55932) read 928

aa ab 03 98 03 e8 01 da 03 e9 02 36 03 ea 3c 51 03 eb 38 20 
03 ec 04 4f 03 ed 02 08 03 ee 01 ce 03 f2 02 5a 03 f3 01 e1 
03 f4 00 1d 03 f5 00 1d 03 f6 02 5a 03 f7 02 19 03 f8 01 ea 
03 f9 01 db 03 fa 00 1e 03 fb 01 e2 03 fc 01 bf 03 fd 01 94 
03 fe 01 df 03 ff 01 f0 04 00 01 b4 04 01 01 bb 04 02 01 e0 
04 03 01 d1 04 04 00 71 04 05 0c a4 04 06 0d 15 04 07 02 2f 
04 08 02 29 04 09 02 4d 04 0a 02 26 04 0b 01 be 04 0c 01 d6 
04 0d 01 fb 04 10 02 1c 04 11 01 df 04 12 01 a8 04 13 01 fe 
04 14 01 b5 04 15 02 09 04 16 02 41 04 1a 27 10 04 1b 27 1c 
04 1c 02 48 04 1d 00 03 04 1e 00 03 04 1f 01 68 04 20 27 10 
04 21 39 3d 04 22 3b 4c 04 23 04 23 04 24 00 14 04 25 00 21 
04 26 00 19 04 27 00 21 04 28 02 42 04 29 01 e0 04 2a 00 03 
04 2b 01 e6 04 2c 01 c3 04 2d 00 1d 04 2e 00 1c 04 2f 01 93 
04 30 01 a0 04 31 01 e8 04 38 01 ed 04 39 02 1e 04 3a 02 0b 
04 3b 02 0e 04 3c 02 10 04 3d 01 a5 04 3e 02 16 04 3f 01 c5 
04 40 00 1d 04 41 00 1e 04 42 00 25 04 43 01 f3 04 44 01 c1 
04 45 02 15 04 46 01 e5 04 47 02 01 04 48 01 d8 04 49 02 3d 
04 4a 01 d1 04 4c 01 ca 04 4d 00 3d 04 4e 01 c8 04 4f 00 1c 
04 50 01 b6 04 51 01 c6 04 52 01 d6 04 53 01 98 04 54 02 4f 
04 b0 01 71 04 b1 01 c8 04 b2 01 ea 04 b3 00 19 04 b4 01 e3 
04 b5 01 c6 04 b6 02 00 04 b7 02 3e 04 b8 02 19 04 b9 02 51 
04 ba 02 10 04 bb 01 96 04 bc 02 54 05 14 02 5e 05 15 01 e6 
05 16 02 12 05 17 01 d5 05 18 01 e0 05 19 01 e4 05 1a 01 98 
05 1b 01 f6 05 1c 01 95 05 1d 01 e3 05 1e 02 0f 05 1f 01 ed 
05 20 01 ba 05 21 02 03 05 22 01 e0 05 78 01 86 05 79 01 ed 
05 7a 01 d1 05 7b 02 15 05 7c 02 04 05 7d 01 96 05 7e 01 d7 
05 7f 02 09 05 80 02 21 05 81 01 d4 05 82 01 91 05 83 02 43 
05 84 01 ee 05 85 01 e4 05 86 01 ff 05 87 02 35 05 88 01 e4 
05 89 01 f0 05 8a 02 06 05 8b 01 c5 05 8c 01 a4 05 8d 02 20 
05 8e 01 f2 05 8f 02 16 05 90 02 55 05 91 01 c2 05 92 01 73 
05 93 02 03 05 94 01 6e 05 95 01 c6 05 96 01 d2 05 97 02 02 
05 98 01 d8 05 99 01 cb 05 dc 02 9d 05 dd 01 cb 05 de 01 e4 
05 df 01 ef 05 e0 01 ec 05 e1 01 ec 05 e2 01 dd 05 e3 01 f6 
05 e4 01 e5 05 e5 02 48 05 e6 02 04 05 e7 01 cc 05 e8 01 ba 
05 e9 01 f2 05 ea 02 54 05 eb 01 c0 06 40 01 f4 06 41 02 08 
06 42 01 fa 06 43 02 07 06 44 02 23 06 45 02 26 06 46 01 8d 
06 a4 01 ea 06 a5 01 ea 07 08 01 f5 07 09 01 b9 07 0a 02 02 
07 0b 01 e9 07 0c 02 06 07 0d 02 31 07 0e 01 fc 07 0f 02 1d 
07 10 02 1c 07 11 02 1e 07 12 02 18 07 13 02 02 07 14 02 16 
07 15 01 d8 07 6c 01 ed 07 6d 01 ea 07 6e 02 17 07 6f 01 ff 
07 d0 02 30 07 d1 01 d9 07 d2 01 e9 07 da 3c c3 07 db 3a f7 
07 dc 02 39 07 dd 3a ad 07 de 00 17 07 df 00 26 07 e0 00 22 
07 e1 00 21 07 e2 01 f7 07 e3 00 1e 07 e4 00 19 07 e5 02 02 
07 e6 01 9e 07 e7 01 de 07 e8 02 12 07 ee 3a 60 07 ef 38 da 
07 f0 02 4d 07 f1 01 e6 07 f2 01 c9 07 f3 39 fd 07 f4 36 a4 
07 f5 02 10 07 f6 01 8c 07 f7 01 c7 07 f8 02 30 07 f9 39 b8 
07 fa 01 cb e8 bb ab aa 
2020/04/20 14:23:28.631 192.168.144.144:30304:30304 UDP& (from 192.168.144.144:47912) read 928

aa ab 03 98 03 e8 02 63 03 e9 01 d7 03 ea 3d 11 03 eb 38 fc 
03 ec 04 53 03 ed 02 15 03 ee 02 04 03 f2 01 c1 03 f3 01 f0 
03 f4 00 1e 03 f5 00 22 03 f6 01 c1 03 f7 01 f7 03 f8 02 6c 
03 f9 01 c9 03 fa 00 21 03 fb 02 05 03 fc 02 57 03 fd 02 06 
03 fe 01 d7 03 ff 01 f2 04 00 01 f0 04 01 01 b4 04 02 01 fe 
04 03 01 eb 04 04 00 90 04 05 0c ac 04 06 0d 04 04 07 02 33 
04 08 01 9d 04 09 01 b8 04 0a 01 ca 04 0b 01 ad 04 0c 01 c9 
04 0d 02 00 04 10 01 c9 04 11 02 16 04 12 01 a2 04 13 01 dc 
04 14 01 f8 04 15 01 ba 04 16 02 0f 04 1a 27 10 04 1b 27 3a 
04 1c 01 f7 04 1d 00 03 04 1e 00 03 04 1f 01 68 04 20 27 10 
04 21 3b b4 04 22 39 ff 04 23 00 00 04 24 00 13 04 25 00 20 
04 26 00 20 04 27 00 1c 04 28 02 12 04 29 02 2f 04 2a 00 97 
04 2b 01 7b 04 2c 01 c1 04 2d 00 1c 04 2e 00 26 04 2f 01 b5 
04 30 01 de 04 31 02 13 04 38 01 e3 04 39 01 cd 04 3a 02 3d 
04 3b 01 ba 04 3c 01 e7 04 3d 01 6e 04 3e 01 d9 04 3f 02 52 
04 40 00 22 04 41 00 1f 04 42 00 1f 04 43 01 e5 04 44 02 3e 
04 45 02 0b 04 46 01 fd 04 47 01 e0 04 48 02 00 04 49 01 b4 
04 4a 02 1a 04 4c 02 1a 04 4d 00 38 04 4e 02 07 04 4f 00 20 
04 50 02 01 04 51 01 7a 04 52 02 09 04 53 02 40 04 54 01 c1 
04 b0 02 38 04 b1 02 27 04 b2 02 08 04 b3 00 2a 04 b4 02 46 
04 b5 02 16 04 b6 01 c5 04 b7 01 f3 04 b8 01 f8 04 b9 01 b4 
04 ba 01 d0 04 bb 01 da 04 bc 02 01 05 14 02 26 05 15 02 4a 
05 16 01 b2 05 17 02 6c 05 18 01 f9 05 19 01 ff 05 1a 02 39 
05 1b 02 2d 05 1c 01 c1 05 1d 02 6a 05 1e 02 29 05 1f 01 ce 
05 20 02 01 05 21 01 80 05 22 01 f3 05 78 02 2d 05 79 01 a4 
05 7a 01 ad 05 7b 02 01 05 7c 01 f9 05 7d 02 02 05 7e 01 e6 
05 7f 01 fa 05 80 01 6b 05 81 01 cf 05 82 02 0d 05 83 01 f4 
05 84 02 2a 05 85 01 ca 05 86 01 eb 05 87 01 fb 05 88 02 38 
05 89 01 de 05 8a 02 4b 05 8b 01 95 05 8c 01 f7 05 8d 01 a4 
05 8e 01 c2 05 8f 02 17 05 90 01 da 05 91 02 40 05 92 01 bc 
05 93 01 e2 05 94 01 d3 05 95 01 7e 05 96 02 1a 05 97 02 0f 
05 98 01 f2 05 99 02 00 05 dc 01 af 05 dd 02 20 05 de 02 17 
05 df 01 f4 05 e0 02 18 05 e1 02 11 05 e2 01 f4 05 e3 01 f2 
05 e4 02 03 05 e5 01 fd 05 e6 01 74 05 e7 01 c3 05 e8 01 c4 
05 e9 01 e3 05 ea 02 08 05 eb 01 fb 06 40 02 22 06 41 01 c5 
06 42 02 3e 06 43 01 ff 06 44 02 20 06 45 01 f5 06 46 02 02 
06 a4 02 04 06 a5 01 ef 07 08 02 03 07 09 02 20 07 0a 01 f9 
07 0b 02 2a 07 0c 02 4c 07 0d 02 2b 07 0e 02 18 07 0f 01 c9 
07 10 01 ea 07 11 02 20 07 12 01 92 07 13 02 00 07 14 02 0e 
07 15 01 ce 07 6c 02 09 07 6d 02 04 07 6e 01 c1 07 6f 02 45 
07 d0 01 cf 07 d1 02 06 07 d2 01 db 07 da 39 d0 07 db 3a 29 
07 dc 01 db 07 dd 35 b1 07 de 00 21 07 df 00 27 07 e0 00 1c 
07 e1 00 1f 07 e2 01 b6 07 e3 00 1b 07 e4 00 1e 07 e5 02 0a 
07 e6 02 19 07 e7 02 19 07 e8 02 05 07 ee 3a 70 07 ef 3c 27 
07 f0 02 21 07 f1 02 4f 07 f2 01 d7 07 f3 39 d5 07 f4 37 9b 
07 f5 01 f0 07 f6 01 cc 07 f7 01 e8 07 f8 02 5c 07 f9 37 b3 
07 fa 01 fc e0 dd ab aa 

The data block is 928 bytes long. Status info is in bytes 4 .. 923. Each datum is 4 bytes long and consists of 2 2-byte integers. First is a parameter code, second is the value. We're looking for parameter code 1028 (0x0404) and either 113 (0x0071) or 144 (0x0090). The controller ID is at the same offset in the data block of each packet. Row 6, 2nd datum: 04 04 00 90

Bytes 104 & 105 must be 0x0404, bytes 106 & 107 must match the desired controller ID number.

Write an asynInterpose layer

That sounds like a plan to implement a filter that should be most reliable.

@prjemian
Copy link
Author

Summary: SO_REUSEPORT socket option (the point of this issue) works. Agree?

@MarkRivers
Copy link
Member

I don't think the asyn driver can access the packet header. But it looks like what you need is the controller ID in the packet. I think you should be able to write an interpose interface that filters messages based on that. You could use asynInterposeFlush.c as a starting point. But rather than overriding the flushIt() method you would override the readIt() method.

@prjemian
Copy link
Author

prjemian commented Apr 20, 2020 via email

@MarkRivers
Copy link
Member

Closed via #109

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

No branches or pull requests

4 participants