Datagram Vector Read Message Count

Upfront I will admit I might be trying to do too many things at once here. I do not know a whole lot about UDP multicast. I know even less about SwiftNIO. My terminology may be wrong but I am going to do my best to explain.

I am trying to implement a WS-Discovery client/library using SwiftNIO.

I based my code on NIOUDPEchoClient and NIOUDPEchoServer.

The problem is that my channelRead seems to be only triggered one time and is only a partial message.

I think I've determined that I have to do .channelOption(ChannelOptions.datagramVectorReadMessageCount, value: 30) and .channelOption(ChannelOptions.recvAllocator, value: FixedSizeRecvByteBufferAllocator(capacity: 30*2048)). Once I do my channelRead has the full body. (It took me longer than I care to admit to realize that datagram is the "D" in UDP...).

The datagramVectorReadMessageCount and recvAllocator are magic to me. I've tried reading the docs but they too are opaque.

Can someone please help me to understand these magic ChannelOptions and point me where I can read about how to come up with sane defaults for the values?

1 Like

I surely can! I'll cover each option in turn.

ChannelOptions.RecvAllocator

This allocator is used to allocate the memory that a Channel will use to write received network data into. This option is only meaningful on Channels that receive data directly from the network. The name is derived from the most basic system call used to receive network data in POSIX systems: recv.

The signature of recv is:

ssize_t recv(int socket, void *buffer, size_t length, int flags);

Notice that this system call requires that the userspace program reading data (in this case, SwiftNIO), must pass a buffer to the kernel for the kernel to write data into. NIO needs to allocate that buffer, and it allows users to influence how it does so by way of the recvAllocator channel option.

A recvAllocator is any type that conforms to the RecvByteBufferAllocator protocol:

/// Allocates `ByteBuffer`s to be used to read bytes from a `Channel` and records the number of the actual bytes that were used.
public protocol RecvByteBufferAllocator {
    /// Allocates a new `ByteBuffer` that will be used to read bytes from a `Channel`.
    func buffer(allocator: ByteBufferAllocator) -> ByteBuffer

    /// Records the actual number of bytes that were read by the last socket call.
    ///
    /// - parameters:
    ///     - actualReadBytes: The number of bytes that were used by the previous allocated `ByteBuffer`
    /// - returns: `true` if the next call to `buffer` may return a bigger buffer then the last call to `buffer`.
    mutating func record(actualReadBytes: Int) -> Bool
}

This protocol is fairly straightforward, containing two functions. The first function, buffer(allocator:) instructs the RecvByteBufferAllocator to use the provided allocator to allocate a ByteBuffer, and returns it to the caller. The second function is used by the Channel to tell the RecvByteBufferAllocator how many bytes were actually read from the network.

What's notable here is that the first call, buffer(allocator:), does not take a size argument. This is the biggest clue for what types that conform to RecvByteBufferAllocator are supposed to do: they are supposed to decide how big a buffer to allocate.

This turns out to be a very important job, because the size of the buffer passed to recv has a fairly profound effect on system behaviour. Consider a system where the remote peer sends small messages over TCP. If NIO was constantly allocating 8kB buffers, even though the actual receives were always 5 or 6 bytes, NIO programs would scale very badly, as each Channel would consume drastically more memory than it needs to.

On the other hand, consider a system using TCP where the remote peer is sending data very quickly. In this system, if we allocate too many small buffers (say, 256 bytes) then we will make far too many system calls to copy data from the kernel. This will slow the program down, making it consume more CPU cycles, and will even slow down data transfer. This is also bad.

The above two examples were with TCP, but the buffer size matters even more for UDP. In UDP, if the buffer that NIO allocates is not large enough to write the entire packet into, the packet will be truncated: the kernel will just throw the rest of the packet data on the floor and return an error (EMSGSIZE).

We can divide the world into strategies. In TCP, we can use the result of the recv system call itself to determine how big the buffer needs to be. If, every time we call recv, we completely fill the buffer, we know it's too small: the remote peer is sending data at least as fast as we're consuming it. We can use that as a signal to make the buffer larger, which will improve throughput. Slower connections will never use larger buffers, and so we can conserve memory. This strategy is implemented by AdaptiveRecvByteBufferAllocator.

In UDP, this is a terrible idea! If the buffer is too small we'll see data loss, and data loss is not great, Bob! More broadly, UDP doesn't meaningfully benefit from tuning the size: each datagram has a fixed maximum size selected by the MTU of the link. For this reason it's faster and safer to just allocate the same size every time, which will be the MTU. This strategy is (sort of) implemented by FixedSizeRecvByteBufferAllocator.

TCP channels in NIO default to using AdaptiveRecvByteBufferAllocator with a minimum size of 64 bytes, an initial size of 2048 bytes, and a maximum size of 65kB. UDP channels in NIO default to using FixedSizeRecvByteBufferAllocator allocating 2kB chunks (safely larger than the usual 1500 byte MTU of ethernet.

ChannelOptions.datagramVectorReadMessageCount

This channel option is used to control how UDP channels perform vector reads. To explain this, we need to step back a moment.

In high performance network programming one of the biggest overheads is the cost of system calls to read and write data. System calls are fairly expensive, entailing a fairly hefty context switch that needs to flush TLBs and generally take steps to protect kernel memory from userspace. To this end, NIO goes to great lengths to minimise the number of system calls it needs to make.

On the outbound side, NIO takes advantage of the writev system call. This is a "vector write" system call. Essentially, it is similar to write, but instead of passing only one buffer of data to send we can pass an array of buffers to send in a single system call. The kernel will copy all of them, in order, into the send buffer, and then return from the system call.

This greatly cheapens the cost of making smaller writes. In NIO we frequently encourage users to make their writes "semantic", to make them correspond to protocol atoms. This means that we will often see many quite small writes. Consider HTTP/1.1 chunked encoding, which looks like this:

1\r\n
a\r\n
6\r\n
series\r\n
2\r\n
of\r\n
5\r\n
small\r\n
writes
\r\n

Assuming the user has sent each of these small words in their own byte buffer, NIO needs to add a buffers for the lengths and the CRLFs. If we didn't have the writev system call, we'd either have to make 3 system calls for each chunk (one for the size + first CRLF, one for the body content, and one for the trailing CRLF) or we'd have to do a lot of memory copying to flatten the messages down. writev reduces the amount of copying and the number of system calls we have to make. It's great! NIO uses this by default, and does not require any input from the user.

So, if vector writes are so great, what about vector reads?

Well, in TCP vector reads aren't very useful. This is because TCP is "stream oriented": there are no inherent message boundaries in TCP. You just read the body like it's a stream of bytes. For this reason, it's just as easy to pass a single giant buffer into the kernel on recv and get the kernel to fill it as it is to pass several smaller ones. For this reason, when we use TCP in NIO, we do not perform vector reads: we perform simple, scalar read calls.

But with UDP, this doesn't work so well. In UDP, each call to recv will give you one (and only one!) datagram. For protocols with lots of small messages, this leads to death by system call overhead: we will end up spending more of our time doing the context switching associated with making system calls than we will actually processing network traffic. Worse, because we'll be so inefficient, we'll likely suffer packet loss as we can't process packets fast enough.

Fortunately, some platforms provide a vector datagram read system call, called recvmmsg. This system call lets us allocate multiple buffers, and to ask the kernel to give us multiple received datagrams at once. On systems that support it, this lets us trade increased memory use for better performance: while we have to allocate more memory at once (to support the maximum possible number of datagrams we could have received), we can vastly reduce the number of system calls we have to make to process the data.

However, unlike with TCP, we don't feel like we can just opt users into this behaviour. As you've seen, if we support reading 30 datagrams at once (not unreasonable), we may need to allocate 30 * 2048 == 61448 bytes of memory per channel. This is quite a lot, especially if you're opening many of them. And unlike TCP we don't do this adaptively (though arguably we could if it proved to be useful).

This is where an unfortunate design comes into play. You see, these two channel options interact with each other.

datagramVectorReadMessageCount does not change the amount of memory a recvAllocator will give us. Indeed, it cannot! The recvAllocator is in charge of how much memory it will allocate. This presents a problem for vector reads. We could call buffer(allocator:) more than once, but there is an implied contract for the RecvByteBufferAllocator implementations that we will not do that. Additionally, that would lead to lots of calls to malloc, an unnecessary slowdown.

So instead, we document that if the user sets the datagramVectorReadMessageCount to a value that isn't 1, they should increase the size of the memory allocated by the FixedSizeRecvByteBufferAllocator correspondingly. This is because, under the hood, we ask the allocator to allocate the memory and then slice it up into datagramVectorReadMessageCount equal sized slices.

In your above example, you set datagramVectorReadMessageCount to 30, and the capacity of FixedSizeRecvByteBufferAllocator to 30 * 2048. This has the effect of allocating a single slab of 61448 bytes. That slab is then partitioned into 30 2048-byte slices, which are passed to the system for a vector read. This allows you to read up to 30 datagrams in a single system call and single call to malloc, vastly increasing throughput at the cost of higher baseline memory consumption.

So, let's talk about this:

The problem is that my channelRead seems to be only triggered one time and is only a partial message.

through the lens of what we've just learned.

The changes you made should not have avoided truncation: we should still have the same maximum size for each datagram, 2kB. We can just read more datagrams faster. So I'm curious as to how this fixed your truncation issue. Can you reproduce the original behaviour? I'd like to see what's going on there.

9 Likes

:drinking_from_fire_hose_emoji: But seriously, thank you, excellent write up. The only thing I fear is that I wish that was in the docs somewhere. I would hate for it to get lost. I will see if I cannot figure out how to help with that.

Sure, I am not sure exactly how to best show this to you. And I am not entirely sure that I am correctly interpreting the results.

But here goes...

Using WireShark I am listening for a response on my network from an IP that I expect to send datagrams on (e.g., ip src host 192.168.137.156). Then I send a WS-Discovery request and wait for the response.

WireShark Packets as Text
  No.     Time           Source                Destination           Protocol Length Info
    1 0.000000       192.168.137.156       192.168.137.184       IPv4     1506   Fragmented IP protocol (proto=UDP 17, off=32, ID=f450) [Reassembled in #4]

  Frame 1: 1506 bytes on wire (12048 bits), 1506 bytes captured (12048 bits) on interface en1, id 0
  Ethernet II, Src: Shenzhen_39:c3:54 (ec:71:db:39:c3:54), Dst: Apple_23:4b:c0 (d4:61:9d:23:4b:c0)
  Internet Protocol Version 4, Src: 192.168.137.156, Dst: 192.168.137.184
  Data (1472 bytes)

  0000  64 69 6e 67 3d 22 55 54 46 2d 38 22 3f 3e 0a 3c   ding="UTF-8"?>.<
  0010  53 4f 41 50 2d 45 4e 56 3a 45 6e 76 65 6c 6f 70   SOAP-ENV:Envelop
  0020  65 20 78 6d 6c 6e 73 3a 53 4f 41 50 2d 45 4e 56   e xmlns:SOAP-ENV
  0030  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 77 33 2e   ="http://www.w3.
  0040  6f 72 67 2f 32 30 30 33 2f 30 35 2f 73 6f 61 70   org/2003/05/soap
  0050  2d 65 6e 76 65 6c 6f 70 65 22 20 78 6d 6c 6e 73   -envelope" xmlns
  0060  3a 53 4f 41 50 2d 45 4e 43 3d 22 68 74 74 70 3a   :SOAP-ENC="http:
  0070  2f 2f 77 77 77 2e 77 33 2e 6f 72 67 2f 32 30 30   //www.w3.org/200
  0080  33 2f 30 35 2f 73 6f 61 70 2d 65 6e 63 6f 64 69   3/05/soap-encodi
  0090  6e 67 22 20 78 6d 6c 6e 73 3a 78 73 69 3d 22 68   ng" xmlns:xsi="h
  00a0  74 74 70 3a 2f 2f 77 77 77 2e 77 33 2e 6f 72 67   ttp://www.w3.org
  00b0  2f 32 30 30 31 2f 58 4d 4c 53 63 68 65 6d 61 2d   /2001/XMLSchema-
  00c0  69 6e 73 74 61 6e 63 65 22 20 78 6d 6c 6e 73 3a   instance" xmlns:
  00d0  78 73 64 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e   xsd="http://www.
  00e0  77 33 2e 6f 72 67 2f 32 30 30 31 2f 58 4d 4c 53   w3.org/2001/XMLS
  00f0  63 68 65 6d 61 22 20 78 6d 6c 6e 73 3a 77 73 61   chema" xmlns:wsa
  0100  3d 22 68 74 74 70 3a 2f 2f 73 63 68 65 6d 61 73   ="http://schemas
  0110  2e 78 6d 6c 73 6f 61 70 2e 6f 72 67 2f 77 73 2f   .xmlsoap.org/ws/
  0120  32 30 30 34 2f 30 38 2f 61 64 64 72 65 73 73 69   2004/08/addressi
  0130  6e 67 22 20 78 6d 6c 6e 73 3a 77 73 64 64 3d 22   ng" xmlns:wsdd="
  0140  68 74 74 70 3a 2f 2f 73 63 68 65 6d 61 73 2e 78   http://schemas.x
  0150  6d 6c 73 6f 61 70 2e 6f 72 67 2f 77 73 2f 32 30   mlsoap.org/ws/20
  0160  30 35 2f 30 34 2f 64 69 73 63 6f 76 65 72 79 22   05/04/discovery"
  0170  20 78 6d 6c 6e 73 3a 77 73 61 35 3d 22 68 74 74    xmlns:wsa5="htt
  0180  70 3a 2f 2f 77 77 77 2e 77 33 2e 6f 72 67 2f 32   p://www.w3.org/2
  0190  30 30 35 2f 30 38 2f 61 64 64 72 65 73 73 69 6e   005/08/addressin
  01a0  67 22 20 78 6d 6c 6e 73 3a 78 6d 69 6d 65 3d 22   g" xmlns:xmime="
  01b0  68 74 74 70 3a 2f 2f 74 65 6d 70 75 72 69 2e 6f   http://tempuri.o
  01c0  72 67 2f 78 6d 69 6d 65 2e 78 73 64 22 20 78 6d   rg/xmime.xsd" xm
  01d0  6c 6e 73 3a 78 6d 69 6d 65 35 3d 22 68 74 74 70   lns:xmime5="http
  01e0  3a 2f 2f 77 77 77 2e 77 33 2e 6f 72 67 2f 32 30   ://www.w3.org/20
  01f0  30 35 2f 30 35 2f 78 6d 6c 6d 69 6d 65 22 20 78   05/05/xmlmime" x
  0200  6d 6c 6e 73 3a 78 6f 70 3d 22 68 74 74 70 3a 2f   mlns:xop="http:/
  0210  2f 77 77 77 2e 77 33 2e 6f 72 67 2f 32 30 30 34   /www.w3.org/2004
  0220  2f 30 38 2f 78 6f 70 2f 69 6e 63 6c 75 64 65 22   /08/xop/include"
  0230  20 78 6d 6c 6e 73 3a 77 73 72 66 62 66 3d 22 68    xmlns:wsrfbf="h
  0240  74 74 70 3a 2f 2f 64 6f 63 73 2e 6f 61 73 69 73   ttp://docs.oasis
  0250  2d 6f 70 65 6e 2e 6f 72 67 2f 77 73 72 66 2f 62   -open.org/wsrf/b
  0260  66 2d 32 22 20 78 6d 6c 6e 73 3a 74 74 3d 22 68   f-2" xmlns:tt="h
  0270  74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e   ttp://www.onvif.
  0280  6f 72 67 2f 76 65 72 31 30 2f 73 63 68 65 6d 61   org/ver10/schema
  0290  22 20 78 6d 6c 6e 73 3a 77 73 74 6f 70 3d 22 68   " xmlns:wstop="h
  02a0  74 74 70 3a 2f 2f 64 6f 63 73 2e 6f 61 73 69 73   ttp://docs.oasis
  02b0  2d 6f 70 65 6e 2e 6f 72 67 2f 77 73 6e 2f 74 2d   -open.org/wsn/t-
  02c0  31 22 20 78 6d 6c 6e 73 3a 77 73 72 66 72 3d 22   1" xmlns:wsrfr="
  02d0  68 74 74 70 3a 2f 2f 64 6f 63 73 2e 6f 61 73 69   http://docs.oasi
  02e0  73 2d 6f 70 65 6e 2e 6f 72 67 2f 77 73 72 66 2f   s-open.org/wsrf/
  02f0  72 2d 32 22 20 78 6d 6c 6e 73 3a 6e 73 31 3d 22   r-2" xmlns:ns1="
  0300  68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66   http://www.onvif
  0310  2e 6f 72 67 2f 76 65 72 31 30 2f 61 63 74 69 6f   .org/ver10/actio
  0320  6e 65 6e 67 69 6e 65 2f 77 73 64 6c 22 20 78 6d   nengine/wsdl" xm
  0330  6c 6e 73 3a 74 65 76 3d 22 68 74 74 70 3a 2f 2f   lns:tev="http://
  0340  77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65   www.onvif.org/ve
  0350  72 31 30 2f 65 76 65 6e 74 73 2f 77 73 64 6c 22   r10/events/wsdl"
  0360  20 78 6d 6c 6e 73 3a 6e 73 31 30 3d 22 68 74 74    xmlns:ns10="htt
  0370  70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72   p://www.onvif.or
  0380  67 2f 76 65 72 31 30 2f 65 76 65 6e 74 73 2f 77   g/ver10/events/w
  0390  73 64 6c 2f 50 75 6c 6c 50 6f 69 6e 74 42 69 6e   sdl/PullPointBin
  03a0  64 69 6e 67 22 20 78 6d 6c 6e 73 3a 6e 73 31 31   ding" xmlns:ns11
  03b0  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76   ="http://www.onv
  03c0  69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 65 76 65   if.org/ver10/eve
  03d0  6e 74 73 2f 77 73 64 6c 2f 43 72 65 61 74 65 50   nts/wsdl/CreateP
  03e0  75 6c 6c 50 6f 69 6e 74 42 69 6e 64 69 6e 67 22   ullPointBinding"
  03f0  20 78 6d 6c 6e 73 3a 6e 73 31 32 3d 22 68 74 74    xmlns:ns12="htt
  0400  70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72   p://www.onvif.or
  0410  67 2f 76 65 72 31 30 2f 65 76 65 6e 74 73 2f 77   g/ver10/events/w
  0420  73 64 6c 2f 50 61 75 73 61 62 6c 65 53 75 62 73   sdl/PausableSubs
  0430  63 72 69 70 74 69 6f 6e 4d 61 6e 61 67 65 72 42   criptionManagerB
  0440  69 6e 64 69 6e 67 22 20 78 6d 6c 6e 73 3a 6e 73   inding" xmlns:ns
  0450  31 33 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f   13="http://www.o
  0460  6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 6e   nvif.org/ver10/n
  0470  65 74 77 6f 72 6b 2f 77 73 64 6c 2f 52 65 6d 6f   etwork/wsdl/Remo
  0480  74 65 44 69 73 63 6f 76 65 72 79 42 69 6e 64 69   teDiscoveryBindi
  0490  6e 67 22 20 78 6d 6c 6e 73 3a 6e 73 31 34 3d 22   ng" xmlns:ns14="
  04a0  68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66   http://www.onvif
  04b0  2e 6f 72 67 2f 76 65 72 31 30 2f 6e 65 74 77 6f   .org/ver10/netwo
  04c0  72 6b 2f 77 73 64 6c 2f 44 69 73 63 6f 76 65 72   rk/wsdl/Discover
  04d0  79 4c 6f 6f 6b 75 70 42 69 6e 64 69 6e 67 22 20   yLookupBinding" 
  04e0  78 6d 6c 6e 73 3a 74 64 6e 3d 22 68 74 74 70 3a   xmlns:tdn="http:
  04f0  2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f   //www.onvif.org/
  0500  76 65 72 31 30 2f 6e 65 74 77 6f 72 6b 2f 77 73   ver10/network/ws
  0510  64 6c 22 20 78 6d 6c 6e 73 3a 6e 73 33 3d 22 68   dl" xmlns:ns3="h
  0520  74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e   ttp://www.onvif.
  0530  6f 72 67 2f 76 65 72 32 30 2f 61 6e 61 6c 79 74   org/ver20/analyt
  0540  69 63 73 2f 77 73 64 6c 2f 52 75 6c 65 45 6e 67   ics/wsdl/RuleEng
  0550  69 6e 65 42 69 6e 64 69 6e 67 22 20 78 6d 6c 6e   ineBinding" xmln
  0560  73 3a 6e 73 34 3d 22 68 74 74 70 3a 2f 2f 77 77   s:ns4="http://ww
  0570  77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 32   w.onvif.org/ver2
  0580  30 2f 61 6e 61 6c 79 74 69 63 73 2f 77 73 64 6c   0/analytics/wsdl
  0590  2f 41 6e 61 6c 79 74 69 63 73 45 6e 67 69 6e 65   /AnalyticsEngine
  05a0  42 69 6e 64 69 6e 67 22 20 78 6d 6c 6e 73 3a 74   Binding" xmlns:t
  05b0  61 6e 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f   an="http://www.o

  No.     Time           Source                Destination           Protocol Length Info
        2 0.000003       192.168.137.156       192.168.137.184       IPv4     1506   Fragmented IP protocol (proto=UDP 17, off=1504, ID=f450) [Reassembled in #4]

  Frame 2: 1506 bytes on wire (12048 bits), 1506 bytes captured (12048 bits) on interface en1, id 0
  Ethernet II, Src: Shenzhen_39:c3:54 (ec:71:db:39:c3:54), Dst: Apple_23:4b:c0 (d4:61:9d:23:4b:c0)
  Internet Protocol Version 4, Src: 192.168.137.156, Dst: 192.168.137.184
  Data (1472 bytes)

  0000  6e 76 69 66 2e 6f 72 67 2f 76 65 72 32 30 2f 61   nvif.org/ver20/a
  0010  6e 61 6c 79 74 69 63 73 2f 77 73 64 6c 22 20 78   nalytics/wsdl" x
  0020  6d 6c 6e 73 3a 6e 73 35 3d 22 68 74 74 70 3a 2f   mlns:ns5="http:/
  0030  2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76   /www.onvif.org/v
  0040  65 72 31 30 2f 65 76 65 6e 74 73 2f 77 73 64 6c   er10/events/wsdl
  0050  2f 50 75 6c 6c 50 6f 69 6e 74 53 75 62 73 63 72   /PullPointSubscr
  0060  69 70 74 69 6f 6e 42 69 6e 64 69 6e 67 22 20 78   iptionBinding" x
  0070  6d 6c 6e 73 3a 6e 73 36 3d 22 68 74 74 70 3a 2f   mlns:ns6="http:/
  0080  2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76   /www.onvif.org/v
  0090  65 72 31 30 2f 65 76 65 6e 74 73 2f 77 73 64 6c   er10/events/wsdl
  00a0  2f 45 76 65 6e 74 42 69 6e 64 69 6e 67 22 20 78   /EventBinding" x
  00b0  6d 6c 6e 73 3a 6e 73 37 3d 22 68 74 74 70 3a 2f   mlns:ns7="http:/
  00c0  2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76   /www.onvif.org/v
  00d0  65 72 31 30 2f 65 76 65 6e 74 73 2f 77 73 64 6c   er10/events/wsdl
  00e0  2f 53 75 62 73 63 72 69 70 74 69 6f 6e 4d 61 6e   /SubscriptionMan
  00f0  61 67 65 72 42 69 6e 64 69 6e 67 22 20 78 6d 6c   agerBinding" xml
  0100  6e 73 3a 6e 73 38 3d 22 68 74 74 70 3a 2f 2f 77   ns:ns8="http://w
  0110  77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72   ww.onvif.org/ver
  0120  31 30 2f 65 76 65 6e 74 73 2f 77 73 64 6c 2f 4e   10/events/wsdl/N
  0130  6f 74 69 66 69 63 61 74 69 6f 6e 50 72 6f 64 75   otificationProdu
  0140  63 65 72 42 69 6e 64 69 6e 67 22 20 78 6d 6c 6e   cerBinding" xmln
  0150  73 3a 77 73 6e 74 3d 22 68 74 74 70 3a 2f 2f 64   s:wsnt="http://d
  0160  6f 63 73 2e 6f 61 73 69 73 2d 6f 70 65 6e 2e 6f   ocs.oasis-open.o
  0170  72 67 2f 77 73 6e 2f 62 2d 32 22 20 78 6d 6c 6e   rg/wsn/b-2" xmln
  0180  73 3a 6e 73 39 3d 22 68 74 74 70 3a 2f 2f 77 77   s:ns9="http://ww
  0190  77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31   w.onvif.org/ver1
  01a0  30 2f 65 76 65 6e 74 73 2f 77 73 64 6c 2f 4e 6f   0/events/wsdl/No
  01b0  74 69 66 69 63 61 74 69 6f 6e 43 6f 6e 73 75 6d   tificationConsum
  01c0  65 72 42 69 6e 64 69 6e 67 22 20 78 6d 6c 6e 73   erBinding" xmlns
  01d0  3a 74 61 64 3d 22 68 74 74 70 3a 2f 2f 77 77 77   :tad="http://www
  01e0  2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30   .onvif.org/ver10
  01f0  2f 61 6e 61 6c 79 74 69 63 73 64 65 76 69 63 65   /analyticsdevice
  0200  2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a 74 64 73   /wsdl" xmlns:tds
  0210  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76   ="http://www.onv
  0220  69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 64 65 76   if.org/ver10/dev
  0230  69 63 65 2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a   ice/wsdl" xmlns:
  0240  74 69 6d 67 3d 22 68 74 74 70 3a 2f 2f 77 77 77   timg="http://www
  0250  2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 32 30   .onvif.org/ver20
  0260  2f 69 6d 61 67 69 6e 67 2f 77 73 64 6c 22 20 78   /imaging/wsdl" x
  0270  6d 6c 6e 73 3a 74 6c 73 3d 22 68 74 74 70 3a 2f   mlns:tls="http:/
  0280  2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76   /www.onvif.org/v
  0290  65 72 31 30 2f 64 69 73 70 6c 61 79 2f 77 73 64   er10/display/wsd
  02a0  6c 22 20 78 6d 6c 6e 73 3a 74 6d 64 3d 22 68 74   l" xmlns:tmd="ht
  02b0  74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f   tp://www.onvif.o
  02c0  72 67 2f 76 65 72 31 30 2f 64 65 76 69 63 65 49   rg/ver10/deviceI
  02d0  4f 2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a 74 70   O/wsdl" xmlns:tp
  02e0  74 7a 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f   tz="http://www.o
  02f0  6e 76 69 66 2e 6f 72 67 2f 76 65 72 32 30 2f 70   nvif.org/ver20/p
  0300  74 7a 2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a 74   tz/wsdl" xmlns:t
  0310  72 63 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f   rc="http://www.o
  0320  6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 72   nvif.org/ver10/r
  0330  65 63 6f 72 64 69 6e 67 2f 77 73 64 6c 22 20 78   ecording/wsdl" x
  0340  6d 6c 6e 73 3a 74 72 70 3d 22 68 74 74 70 3a 2f   mlns:trp="http:/
  0350  2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76   /www.onvif.org/v
  0360  65 72 31 30 2f 72 65 70 6c 61 79 2f 77 73 64 6c   er10/replay/wsdl
  0370  22 20 78 6d 6c 6e 73 3a 74 72 74 3d 22 68 74 74   " xmlns:trt="htt
  0380  70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72   p://www.onvif.or
  0390  67 2f 76 65 72 31 30 2f 6d 65 64 69 61 2f 77 73   g/ver10/media/ws
  03a0  64 6c 22 20 78 6d 6c 6e 73 3a 74 72 76 3d 22 68   dl" xmlns:trv="h
  03b0  74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e   ttp://www.onvif.
  03c0  6f 72 67 2f 76 65 72 31 30 2f 72 65 63 65 69 76   org/ver10/receiv
  03d0  65 72 2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a 74   er/wsdl" xmlns:t
  03e0  73 65 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f   se="http://www.o
  03f0  6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 73   nvif.org/ver10/s
  0400  65 61 72 63 68 2f 77 73 64 6c 22 20 78 6d 6c 6e   earch/wsdl" xmln
  0410  73 3a 74 65 72 3d 22 68 74 74 70 3a 2f 2f 77 77   s:ter="http://ww
  0420  77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31   w.onvif.org/ver1
  0430  30 2f 65 72 72 6f 72 22 20 78 6d 6c 6e 73 3a 74   0/error" xmlns:t
  0440  6e 73 31 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e   ns1="http://www.
  0450  6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30 2f   onvif.org/ver10/
  0460  74 6f 70 69 63 73 22 20 78 6d 6c 6e 73 3a 77 73   topics" xmlns:ws
  0470  73 65 3d 22 68 74 74 70 3a 2f 2f 64 6f 63 73 2e   se="http://docs.
  0480  6f 61 73 69 73 2d 6f 70 65 6e 2e 6f 72 67 2f 77   oasis-open.org/w
  0490  73 73 2f 32 30 30 34 2f 30 31 2f 6f 61 73 69 73   ss/2004/01/oasis
  04a0  2d 32 30 30 34 30 31 2d 77 73 73 2d 77 73 73 65   -200401-wss-wsse
  04b0  63 75 72 69 74 79 2d 73 65 63 65 78 74 2d 31 2e   curity-secext-1.
  04c0  30 2e 78 73 64 22 20 78 6d 6c 6e 73 3a 77 73 75   0.xsd" xmlns:wsu
  04d0  3d 22 68 74 74 70 3a 2f 2f 64 6f 63 73 2e 6f 61   ="http://docs.oa
  04e0  73 69 73 2d 6f 70 65 6e 2e 6f 72 67 2f 77 73 73   sis-open.org/wss
  04f0  2f 32 30 30 34 2f 30 31 2f 6f 61 73 69 73 2d 32   /2004/01/oasis-2
  0500  30 30 34 30 31 2d 77 73 73 2d 77 73 73 65 63 75   00401-wss-wssecu
  0510  72 69 74 79 2d 75 74 69 6c 69 74 79 2d 31 2e 30   rity-utility-1.0
  0520  2e 78 73 64 22 3e 3c 53 4f 41 50 2d 45 4e 56 3a   .xsd"><SOAP-ENV:
  0530  48 65 61 64 65 72 3e 3c 77 73 61 3a 4d 65 73 73   Header><wsa:Mess
  0540  61 67 65 49 44 3e 75 75 69 64 3a 32 34 31 39 64   ageID>uuid:2419d
  0550  36 38 61 2d 32 64 64 32 2d 32 31 62 32 2d 61 32   68a-2dd2-21b2-a2
  0560  30 35 2d 65 63 3a 37 31 3a 64 62 3a 33 39 3a 63   05-ec:71:db:39:c
  0570  33 3a 35 34 3c 2f 77 73 61 3a 4d 65 73 73 61 67   3:54</wsa:Messag
  0580  65 49 44 3e 3c 77 73 61 3a 52 65 6c 61 74 65 73   eID><wsa:Relates
  0590  54 6f 3e 75 75 69 64 3a 42 42 34 35 37 31 32 45   To>uuid:BB45712E
  05a0  2d 43 31 30 42 2d 34 36 36 32 2d 39 31 31 30 2d   -C10B-4662-9110-
  05b0  42 37 41 39 35 36 37 43 42 44 32 36 3c 2f 77 73   B7A9567CBD26</ws

  No.     Time           Source                Destination           Protocol Length Info
        3 0.000004       192.168.137.156       192.168.137.184       IPv4     1094   Fragmented IP protocol (proto=UDP 17, off=2976, ID=f450) [Reassembled in #4]

  Frame 3: 1094 bytes on wire (8752 bits), 1094 bytes captured (8752 bits) on interface en1, id 0
  Ethernet II, Src: Shenzhen_39:c3:54 (ec:71:db:39:c3:54), Dst: Apple_23:4b:c0 (d4:61:9d:23:4b:c0)
  Internet Protocol Version 4, Src: 192.168.137.156, Dst: 192.168.137.184
  Data (1060 bytes)

  0000  61 3a 52 65 6c 61 74 65 73 54 6f 3e 3c 77 73 61   a:RelatesTo><wsa
  0010  3a 54 6f 20 53 4f 41 50 2d 45 4e 56 3a 6d 75 73   :To SOAP-ENV:mus
  0020  74 55 6e 64 65 72 73 74 61 6e 64 3d 22 31 22 3e   tUnderstand="1">
  0030  68 74 74 70 3a 2f 2f 73 63 68 65 6d 61 73 2e 78   http://schemas.x
  0040  6d 6c 73 6f 61 70 2e 6f 72 67 2f 77 73 2f 32 30   mlsoap.org/ws/20
  0050  30 34 2f 30 38 2f 61 64 64 72 65 73 73 69 6e 67   04/08/addressing
  0060  2f 72 6f 6c 65 2f 61 6e 6f 6e 79 6d 6f 75 73 3c   /role/anonymous<
  0070  2f 77 73 61 3a 54 6f 3e 3c 77 73 61 3a 41 63 74   /wsa:To><wsa:Act
  0080  69 6f 6e 3e 68 74 74 70 3a 2f 2f 73 63 68 65 6d   ion>http://schem
  0090  61 73 2e 78 6d 6c 73 6f 61 70 2e 6f 72 67 2f 77   as.xmlsoap.org/w
  00a0  73 2f 32 30 30 35 2f 30 34 2f 64 69 73 63 6f 76   s/2005/04/discov
  00b0  65 72 79 2f 50 72 6f 62 65 4d 61 74 63 68 65 73   ery/ProbeMatches
  00c0  3c 2f 77 73 61 3a 41 63 74 69 6f 6e 3e 3c 2f 53   </wsa:Action></S
  00d0  4f 41 50 2d 45 4e 56 3a 48 65 61 64 65 72 3e 3c   OAP-ENV:Header><
  00e0  53 4f 41 50 2d 45 4e 56 3a 42 6f 64 79 3e 3c 77   SOAP-ENV:Body><w
  00f0  73 64 64 3a 50 72 6f 62 65 4d 61 74 63 68 65 73   sdd:ProbeMatches
  0100  3e 3c 77 73 64 64 3a 50 72 6f 62 65 4d 61 74 63   ><wsdd:ProbeMatc
  0110  68 3e 3c 77 73 61 3a 45 6e 64 70 6f 69 6e 74 52   h><wsa:EndpointR
  0120  65 66 65 72 65 6e 63 65 3e 3c 77 73 61 3a 41 64   eference><wsa:Ad
  0130  64 72 65 73 73 3e 75 72 6e 3a 75 75 69 64 3a 32   dress>urn:uuid:2
  0140  34 31 39 64 36 38 61 2d 32 64 64 32 2d 32 31 62   419d68a-2dd2-21b
  0150  32 2d 61 32 30 35 2d 65 63 3a 37 31 3a 64 62 3a   2-a205-ec:71:db:
  0160  33 39 3a 63 33 3a 35 34 3c 2f 77 73 61 3a 41 64   39:c3:54</wsa:Ad
  0170  64 72 65 73 73 3e 3c 77 73 61 3a 52 65 66 65 72   dress><wsa:Refer
  0180  65 6e 63 65 50 72 6f 70 65 72 74 69 65 73 3e 3c   enceProperties><
  0190  2f 77 73 61 3a 52 65 66 65 72 65 6e 63 65 50 72   /wsa:ReferencePr
  01a0  6f 70 65 72 74 69 65 73 3e 3c 77 73 61 3a 52 65   operties><wsa:Re
  01b0  66 65 72 65 6e 63 65 50 61 72 61 6d 65 74 65 72   ferenceParameter
  01c0  73 3e 3c 2f 77 73 61 3a 52 65 66 65 72 65 6e 63   s></wsa:Referenc
  01d0  65 50 61 72 61 6d 65 74 65 72 73 3e 3c 77 73 61   eParameters><wsa
  01e0  3a 50 6f 72 74 54 79 70 65 3e 74 74 6c 3c 2f 77   :PortType>ttl</w
  01f0  73 61 3a 50 6f 72 74 54 79 70 65 3e 3c 2f 77 73   sa:PortType></ws
  0200  61 3a 45 6e 64 70 6f 69 6e 74 52 65 66 65 72 65   a:EndpointRefere
  0210  6e 63 65 3e 3c 77 73 64 64 3a 54 79 70 65 73 3e   nce><wsdd:Types>
  0220  74 64 6e 3a 4e 65 74 77 6f 72 6b 56 69 64 65 6f   tdn:NetworkVideo
  0230  54 72 61 6e 73 6d 69 74 74 65 72 3c 2f 77 73 64   Transmitter</wsd
  0240  64 3a 54 79 70 65 73 3e 3c 77 73 64 64 3a 53 63   d:Types><wsdd:Sc
  0250  6f 70 65 73 3e 20 6f 6e 76 69 66 3a 2f 2f 77 77   opes> onvif://ww
  0260  77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 74 79 70 65   w.onvif.org/type
  0270  2f 76 69 64 65 6f 5f 65 6e 63 6f 64 65 72 20 6f   /video_encoder o
  0280  6e 76 69 66 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66   nvif://www.onvif
  0290  2e 6f 72 67 2f 6c 6f 63 61 74 69 6f 6e 2f 63 6f   .org/location/co
  02a0  75 6e 74 72 79 2f 63 68 69 6e 61 20 6f 6e 76 69   untry/china onvi
  02b0  66 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72   f://www.onvif.or
  02c0  67 2f 74 79 70 65 2f 6e 65 74 77 6f 72 6b 5f 76   g/type/network_v
  02d0  69 64 65 6f 5f 74 72 61 6e 73 6d 69 74 74 65 72   ideo_transmitter
  02e0  20 6f 6e 76 69 66 3a 2f 2f 77 77 77 2e 6f 6e 76    onvif://www.onv
  02f0  69 66 2e 6f 72 67 2f 68 61 72 64 77 61 72 65 2f   if.org/hardware/
  0300  49 50 43 2d 31 32 32 20 6f 6e 76 69 66 3a 2f 2f   IPC-122 onvif://
  0310  77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 50 72   www.onvif.org/Pr
  0320  6f 66 69 6c 65 2f 53 74 72 65 61 6d 69 6e 67 20   ofile/Streaming 
  0330  6f 6e 76 69 66 3a 2f 2f 77 77 77 2e 6f 6e 76 69   onvif://www.onvi
  0340  66 2e 6f 72 67 2f 6e 61 6d 65 2f 49 50 43 2d 42   f.org/name/IPC-B
  0350  4f 3c 2f 77 73 64 64 3a 53 63 6f 70 65 73 3e 3c   O</wsdd:Scopes><
  0360  77 73 64 64 3a 58 41 64 64 72 73 3e 68 74 74 70   wsdd:XAddrs>http
  0370  3a 2f 2f 31 39 32 2e 31 36 38 2e 31 33 37 2e 31   ://192.168.137.1
  0380  35 36 3a 38 30 30 30 2f 6f 6e 76 69 66 2f 64 65   56:8000/onvif/de
  0390  76 69 63 65 5f 73 65 72 76 69 63 65 3c 2f 77 73   vice_service</ws
  03a0  64 64 3a 58 41 64 64 72 73 3e 3c 77 73 64 64 3a   dd:XAddrs><wsdd:
  03b0  4d 65 74 61 64 61 74 61 56 65 72 73 69 6f 6e 3e   MetadataVersion>
  03c0  31 3c 2f 77 73 64 64 3a 4d 65 74 61 64 61 74 61   1</wsdd:Metadata
  03d0  56 65 72 73 69 6f 6e 3e 3c 2f 77 73 64 64 3a 50   Version></wsdd:P
  03e0  72 6f 62 65 4d 61 74 63 68 3e 3c 2f 77 73 64 64   robeMatch></wsdd
  03f0  3a 50 72 6f 62 65 4d 61 74 63 68 65 73 3e 3c 2f   :ProbeMatches></
  0400  53 4f 41 50 2d 45 4e 56 3a 42 6f 64 79 3e 3c 2f   SOAP-ENV:Body></
  0410  53 4f 41 50 2d 45 4e 56 3a 45 6e 76 65 6c 6f 70   SOAP-ENV:Envelop
  0420  65 3e 0d 0a                                       e>..

In WireShark I see 3 lines:

  1. Fragmented IP protocol (proto=UDP 17, off=32, ID=f450) [Reassembled in #4]
  2. Fragmented IP protocol (proto=UDP 17, off=1504, ID=f450) [Reassembled in #4]
  3. Fragmented IP protocol (proto=UDP 17, off=2976, ID=f450) [Reassembled in #4]

Each of these 3 lines represents a small portion of the overall data I expect to receive. There is a 4th line 3702 → 3702 Len=4028 that seems to be all of the data I expected to receive.

In my Swift code I only ever see the first message. I never see 2-4.

Unless, I turn on:

.channelOption(ChannelOptions.datagramVectorReadMessageCount, value: 30)
.channelOption(ChannelOptions.recvAllocator, value: FixedSizeRecvByteBufferAllocator(capacity: 30*2048))

Now I do freely admit this could be incidental due to the fact that I know next to nothing about UDP or SwiftNIO and UDP being a non-delivery guaranteed protocol. But it feels very consistent.

I am adding the 4th WireShark packet here just because it would not go in the first post (it put me over the limit).

WireShark Packets as Text
  No.     Time           Source                Destination           Protocol Length Info
        4 0.000004       192.168.137.156       192.168.137.184       UDP      66     3702 → 3702 Len=4028

  Frame 4: 66 bytes on wire (528 bits), 66 bytes captured (528 bits) on interface en1, id 0
  Ethernet II, Src: Shenzhen_39:c3:54 (ec:71:db:39:c3:54), Dst: Apple_23:4b:c0 (d4:61:9d:23:4b:c0)
  Internet Protocol Version 4, Src: 192.168.137.156, Dst: 192.168.137.184
  User Datagram Protocol, Src Port: 3702, Dst Port: 3702
  Data (4028 bytes)

  0000  3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31   <?xml version="1
  0010  2e 30 22 20 65 6e 63 6f 64 69 6e 67 3d 22 55 54   .0" encoding="UT
  0020  46 2d 38 22 3f 3e 0a 3c 53 4f 41 50 2d 45 4e 56   F-8"?>.<SOAP-ENV
  0030  3a 45 6e 76 65 6c 6f 70 65 20 78 6d 6c 6e 73 3a   :Envelope xmlns:
  0040  53 4f 41 50 2d 45 4e 56 3d 22 68 74 74 70 3a 2f   SOAP-ENV="http:/
  0050  2f 77 77 77 2e 77 33 2e 6f 72 67 2f 32 30 30 33   /www.w3.org/2003
  0060  2f 30 35 2f 73 6f 61 70 2d 65 6e 76 65 6c 6f 70   /05/soap-envelop
  0070  65 22 20 78 6d 6c 6e 73 3a 53 4f 41 50 2d 45 4e   e" xmlns:SOAP-EN
  0080  43 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 77 33   C="http://www.w3
  0090  2e 6f 72 67 2f 32 30 30 33 2f 30 35 2f 73 6f 61   .org/2003/05/soa
  00a0  70 2d 65 6e 63 6f 64 69 6e 67 22 20 78 6d 6c 6e   p-encoding" xmln
  00b0  73 3a 78 73 69 3d 22 68 74 74 70 3a 2f 2f 77 77   s:xsi="http://ww
  00c0  77 2e 77 33 2e 6f 72 67 2f 32 30 30 31 2f 58 4d   w.w3.org/2001/XM
  00d0  4c 53 63 68 65 6d 61 2d 69 6e 73 74 61 6e 63 65   LSchema-instance
  00e0  22 20 78 6d 6c 6e 73 3a 78 73 64 3d 22 68 74 74   " xmlns:xsd="htt
  00f0  70 3a 2f 2f 77 77 77 2e 77 33 2e 6f 72 67 2f 32   p://www.w3.org/2
  0100  30 30 31 2f 58 4d 4c 53 63 68 65 6d 61 22 20 78   001/XMLSchema" x
  0110  6d 6c 6e 73 3a 77 73 61 3d 22 68 74 74 70 3a 2f   mlns:wsa="http:/
  0120  2f 73 63 68 65 6d 61 73 2e 78 6d 6c 73 6f 61 70   /schemas.xmlsoap
  0130  2e 6f 72 67 2f 77 73 2f 32 30 30 34 2f 30 38 2f   .org/ws/2004/08/
  0140  61 64 64 72 65 73 73 69 6e 67 22 20 78 6d 6c 6e   addressing" xmln
  0150  73 3a 77 73 64 64 3d 22 68 74 74 70 3a 2f 2f 73   s:wsdd="http://s
  0160  63 68 65 6d 61 73 2e 78 6d 6c 73 6f 61 70 2e 6f   chemas.xmlsoap.o
  0170  72 67 2f 77 73 2f 32 30 30 35 2f 30 34 2f 64 69   rg/ws/2005/04/di
  0180  73 63 6f 76 65 72 79 22 20 78 6d 6c 6e 73 3a 77   scovery" xmlns:w
  0190  73 61 35 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e   sa5="http://www.
  01a0  77 33 2e 6f 72 67 2f 32 30 30 35 2f 30 38 2f 61   w3.org/2005/08/a
  01b0  64 64 72 65 73 73 69 6e 67 22 20 78 6d 6c 6e 73   ddressing" xmlns
  01c0  3a 78 6d 69 6d 65 3d 22 68 74 74 70 3a 2f 2f 74   :xmime="http://t
  01d0  65 6d 70 75 72 69 2e 6f 72 67 2f 78 6d 69 6d 65   empuri.org/xmime
  01e0  2e 78 73 64 22 20 78 6d 6c 6e 73 3a 78 6d 69 6d   .xsd" xmlns:xmim
  01f0  65 35 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 77   e5="http://www.w
  0200  33 2e 6f 72 67 2f 32 30 30 35 2f 30 35 2f 78 6d   3.org/2005/05/xm
  0210  6c 6d 69 6d 65 22 20 78 6d 6c 6e 73 3a 78 6f 70   lmime" xmlns:xop
  0220  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 77 33 2e   ="http://www.w3.
  0230  6f 72 67 2f 32 30 30 34 2f 30 38 2f 78 6f 70 2f   org/2004/08/xop/
  0240  69 6e 63 6c 75 64 65 22 20 78 6d 6c 6e 73 3a 77   include" xmlns:w
  0250  73 72 66 62 66 3d 22 68 74 74 70 3a 2f 2f 64 6f   srfbf="http://do
  0260  63 73 2e 6f 61 73 69 73 2d 6f 70 65 6e 2e 6f 72   cs.oasis-open.or
  0270  67 2f 77 73 72 66 2f 62 66 2d 32 22 20 78 6d 6c   g/wsrf/bf-2" xml
  0280  6e 73 3a 74 74 3d 22 68 74 74 70 3a 2f 2f 77 77   ns:tt="http://ww
  0290  77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31   w.onvif.org/ver1
  02a0  30 2f 73 63 68 65 6d 61 22 20 78 6d 6c 6e 73 3a   0/schema" xmlns:
  02b0  77 73 74 6f 70 3d 22 68 74 74 70 3a 2f 2f 64 6f   wstop="http://do
  02c0  63 73 2e 6f 61 73 69 73 2d 6f 70 65 6e 2e 6f 72   cs.oasis-open.or
  02d0  67 2f 77 73 6e 2f 74 2d 31 22 20 78 6d 6c 6e 73   g/wsn/t-1" xmlns
  02e0  3a 77 73 72 66 72 3d 22 68 74 74 70 3a 2f 2f 64   :wsrfr="http://d
  02f0  6f 63 73 2e 6f 61 73 69 73 2d 6f 70 65 6e 2e 6f   ocs.oasis-open.o
  0300  72 67 2f 77 73 72 66 2f 72 2d 32 22 20 78 6d 6c   rg/wsrf/r-2" xml
  0310  6e 73 3a 6e 73 31 3d 22 68 74 74 70 3a 2f 2f 77   ns:ns1="http://w
  0320  77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72   ww.onvif.org/ver
  0330  31 30 2f 61 63 74 69 6f 6e 65 6e 67 69 6e 65 2f   10/actionengine/
  0340  77 73 64 6c 22 20 78 6d 6c 6e 73 3a 74 65 76 3d   wsdl" xmlns:tev=
  0350  22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69   "http://www.onvi
  0360  66 2e 6f 72 67 2f 76 65 72 31 30 2f 65 76 65 6e   f.org/ver10/even
  0370  74 73 2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a 6e   ts/wsdl" xmlns:n
  0380  73 31 30 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e   s10="http://www.
  0390  6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30 2f   onvif.org/ver10/
  03a0  65 76 65 6e 74 73 2f 77 73 64 6c 2f 50 75 6c 6c   events/wsdl/Pull
  03b0  50 6f 69 6e 74 42 69 6e 64 69 6e 67 22 20 78 6d   PointBinding" xm
  03c0  6c 6e 73 3a 6e 73 31 31 3d 22 68 74 74 70 3a 2f   lns:ns11="http:/
  03d0  2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76   /www.onvif.org/v
  03e0  65 72 31 30 2f 65 76 65 6e 74 73 2f 77 73 64 6c   er10/events/wsdl
  03f0  2f 43 72 65 61 74 65 50 75 6c 6c 50 6f 69 6e 74   /CreatePullPoint
  0400  42 69 6e 64 69 6e 67 22 20 78 6d 6c 6e 73 3a 6e   Binding" xmlns:n
  0410  73 31 32 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e   s12="http://www.
  0420  6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30 2f   onvif.org/ver10/
  0430  65 76 65 6e 74 73 2f 77 73 64 6c 2f 50 61 75 73   events/wsdl/Paus
  0440  61 62 6c 65 53 75 62 73 63 72 69 70 74 69 6f 6e   ableSubscription
  0450  4d 61 6e 61 67 65 72 42 69 6e 64 69 6e 67 22 20   ManagerBinding" 
  0460  78 6d 6c 6e 73 3a 6e 73 31 33 3d 22 68 74 74 70   xmlns:ns13="http
  0470  3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67   ://www.onvif.org
  0480  2f 76 65 72 31 30 2f 6e 65 74 77 6f 72 6b 2f 77   /ver10/network/w
  0490  73 64 6c 2f 52 65 6d 6f 74 65 44 69 73 63 6f 76   sdl/RemoteDiscov
  04a0  65 72 79 42 69 6e 64 69 6e 67 22 20 78 6d 6c 6e   eryBinding" xmln
  04b0  73 3a 6e 73 31 34 3d 22 68 74 74 70 3a 2f 2f 77   s:ns14="http://w
  04c0  77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72   ww.onvif.org/ver
  04d0  31 30 2f 6e 65 74 77 6f 72 6b 2f 77 73 64 6c 2f   10/network/wsdl/
  04e0  44 69 73 63 6f 76 65 72 79 4c 6f 6f 6b 75 70 42   DiscoveryLookupB
  04f0  69 6e 64 69 6e 67 22 20 78 6d 6c 6e 73 3a 74 64   inding" xmlns:td
  0500  6e 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e   n="http://www.on
  0510  76 69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 6e 65   vif.org/ver10/ne
  0520  74 77 6f 72 6b 2f 77 73 64 6c 22 20 78 6d 6c 6e   twork/wsdl" xmln
  0530  73 3a 6e 73 33 3d 22 68 74 74 70 3a 2f 2f 77 77   s:ns3="http://ww
  0540  77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 32   w.onvif.org/ver2
  0550  30 2f 61 6e 61 6c 79 74 69 63 73 2f 77 73 64 6c   0/analytics/wsdl
  0560  2f 52 75 6c 65 45 6e 67 69 6e 65 42 69 6e 64 69   /RuleEngineBindi
  0570  6e 67 22 20 78 6d 6c 6e 73 3a 6e 73 34 3d 22 68   ng" xmlns:ns4="h
  0580  74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e   ttp://www.onvif.
  0590  6f 72 67 2f 76 65 72 32 30 2f 61 6e 61 6c 79 74   org/ver20/analyt
  05a0  69 63 73 2f 77 73 64 6c 2f 41 6e 61 6c 79 74 69   ics/wsdl/Analyti
  05b0  63 73 45 6e 67 69 6e 65 42 69 6e 64 69 6e 67 22   csEngineBinding"
  05c0  20 78 6d 6c 6e 73 3a 74 61 6e 3d 22 68 74 74 70    xmlns:tan="http
  05d0  3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67   ://www.onvif.org
  05e0  2f 76 65 72 32 30 2f 61 6e 61 6c 79 74 69 63 73   /ver20/analytics
  05f0  2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a 6e 73 35   /wsdl" xmlns:ns5
  0600  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76   ="http://www.onv
  0610  69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 65 76 65   if.org/ver10/eve
  0620  6e 74 73 2f 77 73 64 6c 2f 50 75 6c 6c 50 6f 69   nts/wsdl/PullPoi
  0630  6e 74 53 75 62 73 63 72 69 70 74 69 6f 6e 42 69   ntSubscriptionBi
  0640  6e 64 69 6e 67 22 20 78 6d 6c 6e 73 3a 6e 73 36   nding" xmlns:ns6
  0650  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76   ="http://www.onv
  0660  69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 65 76 65   if.org/ver10/eve
  0670  6e 74 73 2f 77 73 64 6c 2f 45 76 65 6e 74 42 69   nts/wsdl/EventBi
  0680  6e 64 69 6e 67 22 20 78 6d 6c 6e 73 3a 6e 73 37   nding" xmlns:ns7
  0690  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76   ="http://www.onv
  06a0  69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 65 76 65   if.org/ver10/eve
  06b0  6e 74 73 2f 77 73 64 6c 2f 53 75 62 73 63 72 69   nts/wsdl/Subscri
  06c0  70 74 69 6f 6e 4d 61 6e 61 67 65 72 42 69 6e 64   ptionManagerBind
  06d0  69 6e 67 22 20 78 6d 6c 6e 73 3a 6e 73 38 3d 22   ing" xmlns:ns8="
  06e0  68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66   http://www.onvif
  06f0  2e 6f 72 67 2f 76 65 72 31 30 2f 65 76 65 6e 74   .org/ver10/event
  0700  73 2f 77 73 64 6c 2f 4e 6f 74 69 66 69 63 61 74   s/wsdl/Notificat
  0710  69 6f 6e 50 72 6f 64 75 63 65 72 42 69 6e 64 69   ionProducerBindi
  0720  6e 67 22 20 78 6d 6c 6e 73 3a 77 73 6e 74 3d 22   ng" xmlns:wsnt="
  0730  68 74 74 70 3a 2f 2f 64 6f 63 73 2e 6f 61 73 69   http://docs.oasi
  0740  73 2d 6f 70 65 6e 2e 6f 72 67 2f 77 73 6e 2f 62   s-open.org/wsn/b
  0750  2d 32 22 20 78 6d 6c 6e 73 3a 6e 73 39 3d 22 68   -2" xmlns:ns9="h
  0760  74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e   ttp://www.onvif.
  0770  6f 72 67 2f 76 65 72 31 30 2f 65 76 65 6e 74 73   org/ver10/events
  0780  2f 77 73 64 6c 2f 4e 6f 74 69 66 69 63 61 74 69   /wsdl/Notificati
  0790  6f 6e 43 6f 6e 73 75 6d 65 72 42 69 6e 64 69 6e   onConsumerBindin
  07a0  67 22 20 78 6d 6c 6e 73 3a 74 61 64 3d 22 68 74   g" xmlns:tad="ht
  07b0  74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f   tp://www.onvif.o
  07c0  72 67 2f 76 65 72 31 30 2f 61 6e 61 6c 79 74 69   rg/ver10/analyti
  07d0  63 73 64 65 76 69 63 65 2f 77 73 64 6c 22 20 78   csdevice/wsdl" x
  07e0  6d 6c 6e 73 3a 74 64 73 3d 22 68 74 74 70 3a 2f   mlns:tds="http:/
  07f0  2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76   /www.onvif.org/v
  0800  65 72 31 30 2f 64 65 76 69 63 65 2f 77 73 64 6c   er10/device/wsdl
  0810  22 20 78 6d 6c 6e 73 3a 74 69 6d 67 3d 22 68 74   " xmlns:timg="ht
  0820  74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f   tp://www.onvif.o
  0830  72 67 2f 76 65 72 32 30 2f 69 6d 61 67 69 6e 67   rg/ver20/imaging
  0840  2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a 74 6c 73   /wsdl" xmlns:tls
  0850  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76   ="http://www.onv
  0860  69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 64 69 73   if.org/ver10/dis
  0870  70 6c 61 79 2f 77 73 64 6c 22 20 78 6d 6c 6e 73   play/wsdl" xmlns
  0880  3a 74 6d 64 3d 22 68 74 74 70 3a 2f 2f 77 77 77   :tmd="http://www
  0890  2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30   .onvif.org/ver10
  08a0  2f 64 65 76 69 63 65 49 4f 2f 77 73 64 6c 22 20   /deviceIO/wsdl" 
  08b0  78 6d 6c 6e 73 3a 74 70 74 7a 3d 22 68 74 74 70   xmlns:tptz="http
  08c0  3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67   ://www.onvif.org
  08d0  2f 76 65 72 32 30 2f 70 74 7a 2f 77 73 64 6c 22   /ver20/ptz/wsdl"
  08e0  20 78 6d 6c 6e 73 3a 74 72 63 3d 22 68 74 74 70    xmlns:trc="http
  08f0  3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67   ://www.onvif.org
  0900  2f 76 65 72 31 30 2f 72 65 63 6f 72 64 69 6e 67   /ver10/recording
  0910  2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a 74 72 70   /wsdl" xmlns:trp
  0920  3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76   ="http://www.onv
  0930  69 66 2e 6f 72 67 2f 76 65 72 31 30 2f 72 65 70   if.org/ver10/rep
  0940  6c 61 79 2f 77 73 64 6c 22 20 78 6d 6c 6e 73 3a   lay/wsdl" xmlns:
  0950  74 72 74 3d 22 68 74 74 70 3a 2f 2f 77 77 77 2e   trt="http://www.
  0960  6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31 30 2f   onvif.org/ver10/
  0970  6d 65 64 69 61 2f 77 73 64 6c 22 20 78 6d 6c 6e   media/wsdl" xmln
  0980  73 3a 74 72 76 3d 22 68 74 74 70 3a 2f 2f 77 77   s:trv="http://ww
  0990  77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 76 65 72 31   w.onvif.org/ver1
  09a0  30 2f 72 65 63 65 69 76 65 72 2f 77 73 64 6c 22   0/receiver/wsdl"
  09b0  20 78 6d 6c 6e 73 3a 74 73 65 3d 22 68 74 74 70    xmlns:tse="http
  09c0  3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67   ://www.onvif.org
  09d0  2f 76 65 72 31 30 2f 73 65 61 72 63 68 2f 77 73   /ver10/search/ws
  09e0  64 6c 22 20 78 6d 6c 6e 73 3a 74 65 72 3d 22 68   dl" xmlns:ter="h
  09f0  74 74 70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e   ttp://www.onvif.
  0a00  6f 72 67 2f 76 65 72 31 30 2f 65 72 72 6f 72 22   org/ver10/error"
  0a10  20 78 6d 6c 6e 73 3a 74 6e 73 31 3d 22 68 74 74    xmlns:tns1="htt
  0a20  70 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72   p://www.onvif.or
  0a30  67 2f 76 65 72 31 30 2f 74 6f 70 69 63 73 22 20   g/ver10/topics" 
  0a40  78 6d 6c 6e 73 3a 77 73 73 65 3d 22 68 74 74 70   xmlns:wsse="http
  0a50  3a 2f 2f 64 6f 63 73 2e 6f 61 73 69 73 2d 6f 70   ://docs.oasis-op
  0a60  65 6e 2e 6f 72 67 2f 77 73 73 2f 32 30 30 34 2f   en.org/wss/2004/
  0a70  30 31 2f 6f 61 73 69 73 2d 32 30 30 34 30 31 2d   01/oasis-200401-
  0a80  77 73 73 2d 77 73 73 65 63 75 72 69 74 79 2d 73   wss-wssecurity-s
  0a90  65 63 65 78 74 2d 31 2e 30 2e 78 73 64 22 20 78   ecext-1.0.xsd" x
  0aa0  6d 6c 6e 73 3a 77 73 75 3d 22 68 74 74 70 3a 2f   mlns:wsu="http:/
  0ab0  2f 64 6f 63 73 2e 6f 61 73 69 73 2d 6f 70 65 6e   /docs.oasis-open
  0ac0  2e 6f 72 67 2f 77 73 73 2f 32 30 30 34 2f 30 31   .org/wss/2004/01
  0ad0  2f 6f 61 73 69 73 2d 32 30 30 34 30 31 2d 77 73   /oasis-200401-ws
  0ae0  73 2d 77 73 73 65 63 75 72 69 74 79 2d 75 74 69   s-wssecurity-uti
  0af0  6c 69 74 79 2d 31 2e 30 2e 78 73 64 22 3e 3c 53   lity-1.0.xsd"><S
  0b00  4f 41 50 2d 45 4e 56 3a 48 65 61 64 65 72 3e 3c   OAP-ENV:Header><
  0b10  77 73 61 3a 4d 65 73 73 61 67 65 49 44 3e 75 75   wsa:MessageID>uu
  0b20  69 64 3a 32 34 31 39 64 36 38 61 2d 32 64 64 32   id:2419d68a-2dd2
  0b30  2d 32 31 62 32 2d 61 32 30 35 2d 65 63 3a 37 31   -21b2-a205-ec:71
  0b40  3a 64 62 3a 33 39 3a 63 33 3a 35 34 3c 2f 77 73   :db:39:c3:54</ws
  0b50  61 3a 4d 65 73 73 61 67 65 49 44 3e 3c 77 73 61   a:MessageID><wsa
  0b60  3a 52 65 6c 61 74 65 73 54 6f 3e 75 75 69 64 3a   :RelatesTo>uuid:
  0b70  42 42 34 35 37 31 32 45 2d 43 31 30 42 2d 34 36   BB45712E-C10B-46
  0b80  36 32 2d 39 31 31 30 2d 42 37 41 39 35 36 37 43   62-9110-B7A9567C
  0b90  42 44 32 36 3c 2f 77 73 61 3a 52 65 6c 61 74 65   BD26</wsa:Relate
  0ba0  73 54 6f 3e 3c 77 73 61 3a 54 6f 20 53 4f 41 50   sTo><wsa:To SOAP
  0bb0  2d 45 4e 56 3a 6d 75 73 74 55 6e 64 65 72 73 74   -ENV:mustUnderst
  0bc0  61 6e 64 3d 22 31 22 3e 68 74 74 70 3a 2f 2f 73   and="1">http://s
  0bd0  63 68 65 6d 61 73 2e 78 6d 6c 73 6f 61 70 2e 6f   chemas.xmlsoap.o
  0be0  72 67 2f 77 73 2f 32 30 30 34 2f 30 38 2f 61 64   rg/ws/2004/08/ad
  0bf0  64 72 65 73 73 69 6e 67 2f 72 6f 6c 65 2f 61 6e   dressing/role/an
  0c00  6f 6e 79 6d 6f 75 73 3c 2f 77 73 61 3a 54 6f 3e   onymous</wsa:To>
  0c10  3c 77 73 61 3a 41 63 74 69 6f 6e 3e 68 74 74 70   <wsa:Action>http
  0c20  3a 2f 2f 73 63 68 65 6d 61 73 2e 78 6d 6c 73 6f   ://schemas.xmlso
  0c30  61 70 2e 6f 72 67 2f 77 73 2f 32 30 30 35 2f 30   ap.org/ws/2005/0
  0c40  34 2f 64 69 73 63 6f 76 65 72 79 2f 50 72 6f 62   4/discovery/Prob
  0c50  65 4d 61 74 63 68 65 73 3c 2f 77 73 61 3a 41 63   eMatches</wsa:Ac
  0c60  74 69 6f 6e 3e 3c 2f 53 4f 41 50 2d 45 4e 56 3a   tion></SOAP-ENV:
  0c70  48 65 61 64 65 72 3e 3c 53 4f 41 50 2d 45 4e 56   Header><SOAP-ENV
  0c80  3a 42 6f 64 79 3e 3c 77 73 64 64 3a 50 72 6f 62   :Body><wsdd:Prob
  0c90  65 4d 61 74 63 68 65 73 3e 3c 77 73 64 64 3a 50   eMatches><wsdd:P
  0ca0  72 6f 62 65 4d 61 74 63 68 3e 3c 77 73 61 3a 45   robeMatch><wsa:E
  0cb0  6e 64 70 6f 69 6e 74 52 65 66 65 72 65 6e 63 65   ndpointReference
  0cc0  3e 3c 77 73 61 3a 41 64 64 72 65 73 73 3e 75 72   ><wsa:Address>ur
  0cd0  6e 3a 75 75 69 64 3a 32 34 31 39 64 36 38 61 2d   n:uuid:2419d68a-
  0ce0  32 64 64 32 2d 32 31 62 32 2d 61 32 30 35 2d 65   2dd2-21b2-a205-e
  0cf0  63 3a 37 31 3a 64 62 3a 33 39 3a 63 33 3a 35 34   c:71:db:39:c3:54
  0d00  3c 2f 77 73 61 3a 41 64 64 72 65 73 73 3e 3c 77   </wsa:Address><w
  0d10  73 61 3a 52 65 66 65 72 65 6e 63 65 50 72 6f 70   sa:ReferenceProp
  0d20  65 72 74 69 65 73 3e 3c 2f 77 73 61 3a 52 65 66   erties></wsa:Ref
  0d30  65 72 65 6e 63 65 50 72 6f 70 65 72 74 69 65 73   erenceProperties
  0d40  3e 3c 77 73 61 3a 52 65 66 65 72 65 6e 63 65 50   ><wsa:ReferenceP
  0d50  61 72 61 6d 65 74 65 72 73 3e 3c 2f 77 73 61 3a   arameters></wsa:
  0d60  52 65 66 65 72 65 6e 63 65 50 61 72 61 6d 65 74   ReferenceParamet
  0d70  65 72 73 3e 3c 77 73 61 3a 50 6f 72 74 54 79 70   ers><wsa:PortTyp
  0d80  65 3e 74 74 6c 3c 2f 77 73 61 3a 50 6f 72 74 54   e>ttl</wsa:PortT
  0d90  79 70 65 3e 3c 2f 77 73 61 3a 45 6e 64 70 6f 69   ype></wsa:Endpoi
  0da0  6e 74 52 65 66 65 72 65 6e 63 65 3e 3c 77 73 64   ntReference><wsd
  0db0  64 3a 54 79 70 65 73 3e 74 64 6e 3a 4e 65 74 77   d:Types>tdn:Netw
  0dc0  6f 72 6b 56 69 64 65 6f 54 72 61 6e 73 6d 69 74   orkVideoTransmit
  0dd0  74 65 72 3c 2f 77 73 64 64 3a 54 79 70 65 73 3e   ter</wsdd:Types>
  0de0  3c 77 73 64 64 3a 53 63 6f 70 65 73 3e 20 6f 6e   <wsdd:Scopes> on
  0df0  76 69 66 3a 2f 2f 77 77 77 2e 6f 6e 76 69 66 2e   vif://www.onvif.
  0e00  6f 72 67 2f 74 79 70 65 2f 76 69 64 65 6f 5f 65   org/type/video_e
  0e10  6e 63 6f 64 65 72 20 6f 6e 76 69 66 3a 2f 2f 77   ncoder onvif://w
  0e20  77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 6c 6f 63   ww.onvif.org/loc
  0e30  61 74 69 6f 6e 2f 63 6f 75 6e 74 72 79 2f 63 68   ation/country/ch
  0e40  69 6e 61 20 6f 6e 76 69 66 3a 2f 2f 77 77 77 2e   ina onvif://www.
  0e50  6f 6e 76 69 66 2e 6f 72 67 2f 74 79 70 65 2f 6e   onvif.org/type/n
  0e60  65 74 77 6f 72 6b 5f 76 69 64 65 6f 5f 74 72 61   etwork_video_tra
  0e70  6e 73 6d 69 74 74 65 72 20 6f 6e 76 69 66 3a 2f   nsmitter onvif:/
  0e80  2f 77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 68   /www.onvif.org/h
  0e90  61 72 64 77 61 72 65 2f 49 50 43 2d 31 32 32 20   ardware/IPC-122 
  0ea0  6f 6e 76 69 66 3a 2f 2f 77 77 77 2e 6f 6e 76 69   onvif://www.onvi
  0eb0  66 2e 6f 72 67 2f 50 72 6f 66 69 6c 65 2f 53 74   f.org/Profile/St
  0ec0  72 65 61 6d 69 6e 67 20 6f 6e 76 69 66 3a 2f 2f   reaming onvif://
  0ed0  77 77 77 2e 6f 6e 76 69 66 2e 6f 72 67 2f 6e 61   www.onvif.org/na
  0ee0  6d 65 2f 49 50 43 2d 42 4f 3c 2f 77 73 64 64 3a   me/IPC-BO</wsdd:
  0ef0  53 63 6f 70 65 73 3e 3c 77 73 64 64 3a 58 41 64   Scopes><wsdd:XAd
  0f00  64 72 73 3e 68 74 74 70 3a 2f 2f 31 39 32 2e 31   drs>http://192.1
  0f10  36 38 2e 31 33 37 2e 31 35 36 3a 38 30 30 30 2f   68.137.156:8000/
  0f20  6f 6e 76 69 66 2f 64 65 76 69 63 65 5f 73 65 72   onvif/device_ser
  0f30  76 69 63 65 3c 2f 77 73 64 64 3a 58 41 64 64 72   vice</wsdd:XAddr
  0f40  73 3e 3c 77 73 64 64 3a 4d 65 74 61 64 61 74 61   s><wsdd:Metadata
  0f50  56 65 72 73 69 6f 6e 3e 31 3c 2f 77 73 64 64 3a   Version>1</wsdd:
  0f60  4d 65 74 61 64 61 74 61 56 65 72 73 69 6f 6e 3e   MetadataVersion>
  0f70  3c 2f 77 73 64 64 3a 50 72 6f 62 65 4d 61 74 63   </wsdd:ProbeMatc
  0f80  68 3e 3c 2f 77 73 64 64 3a 50 72 6f 62 65 4d 61   h></wsdd:ProbeMa
  0f90  74 63 68 65 73 3e 3c 2f 53 4f 41 50 2d 45 4e 56   tches></SOAP-ENV
  0fa0  3a 42 6f 64 79 3e 3c 2f 53 4f 41 50 2d 45 4e 56   :Body></SOAP-ENV
  0fb0  3a 45 6e 76 65 6c 6f 70 65 3e 0d 0a               :Envelope>..

Oh, the packets are fragmented. This explains the issue.

So, in the above description I omitted something important. Regarding datagramVectorReadMessageCount I said this:

macOS is not one of those platforms! Indeed, on macOS we have an exploding shim for the function. So on macOS, under the hood we're seeing you set the vector read size to 30 and just ignoring it:

case _ as ChannelOptions.Types.DatagramVectorReadMessageCountOption:
    // We only support vector reads on these OSes. Let us know if there's another OS with this syscall!
    #if os(Linux) || os(FreeBSD) || os(Android)
    self.vectorReadManager.updateMessageCount(value as! Int)
    #else
    break
    #endif

However, we don't ignore the update to the RecvByteBufferAllocator: that still applies. This is the clue.

The secret here is that the UDP packet in question is actually really large: much larger than the MTU. You can see this in the Wireshark reassembly (occurring in packet 4) where Wireshark synthesises a fake UDP packet with Data (4028 bytes). This is a 4028-byte UDP datagram. But your network has a 1500-byte MTU. This forces the datagram to be spread across a number of IP fragments.

macOS is reassembling this UDP datagram into a single, 4028-byte datagram, and delivering that in a single shot to user space. But by default we only have a 2kB buffer, so this packet gets truncated. When you increased the size of the allocator to 60kB, there was now space for this datagram! Turns out the vector reads are a red herring here, but the allocator size is not.

I didn't propose this theory earlier because, frankly, IP fragmentation is fairly unusual. Most protocols try to perform MTU discovery and then fragment at the application layer because it's quite common for fragmented packets to fail to traverse network boundaries.

In this case, you can remove the vector read change and just set the buffer size to something somewhat reasonable. UDP has a 16-bit packet length so the absolute fallback is 64kB, which will definitely hold any UDP packet irregardless of how big it gets. In this case you're likely to use very few channels so it's probably fine to have slightly excessive memory use here.

Regarding this, the solution is to add the writeup to the doc comments on the channel options in the repository. I'll happily review a patch that does that.

:bulb: I was confused by the readout from Wireshark. The fragment lines made me believe I was expecting 3 separate calls to channelRead. I was expecting that I would have to reassemble the fragments into a single message. I was not expecting macOS to get it all into a single packet and trigger one call.

Is this reassembling of the fragmented datagrams into a single datagram typical behavior I can count on in practice? Or does my library need to expect the IP fragmentation and attempt to handle it?

I have the sneaky (scary) feeling the answer is "it depends".

It does beg the question: is the unusual IP fragmentation just a quirk of the PoE hardware I am using, a quirk of the WS-Discovery protocol, or just my network (mis) configuration. Alas, I think it's out of scope for this forum and out of my ability to properly debug.

The answer is probably largely academic if my goal is to write a general purpose library from doing WS-Discovery in SwiftNIO as I could not possibly know all the configurations of the hardware and networks. But tracking the answer down might be instructive for learning.

The "reasonable" default is definitely a concern as I am not nearly qualified to decide that. I can confirm that making my FixedSizeRecvByteBufferAllocator have any capacity of 4028 bytes or larger and the message no longer truncates. So I feel I have experimented enough to empirically show all that you have explained to me thus far.

I am inclined to make it 4KiB or 8KiB and call it good enough. Though I dislike "magic numbers" and 2kB and 64kB (or any other I might choose) feels like it will be pure magic. Can you point to where SwiftNIO codes its default of 2kB chunks for FixedSizeRecvByteBufferAllocator? I'd like to see how it is documented for future maintainers just to see if it might give me a good example of how to do it.

So long as you're operating at the UDP layer, this is not your problem, it's a problem for the OS. If you have to travel over "the actual internet" then in general IP fragment reassembly will fail, but otherwise you can just ignore that it's even a thing.

Quite the opposite: it's unusual because many malfunctioning routers fail to handle fragmented IP packets! The problem is that when you fragment an IP packet the layer 4 headers (e.g. UDP header, TCP header) are only in one of the fragments. Routers that don't do a careful job of packet reassembly will barf, expecting to find layer 4 headers that aren't there. On local networks like yours IP fragmentation is much more likely to succeed, which is why we actually observed a fragmented inbound IP packet.

It's definitely coded as a magic number. :wink: We do it here and here with no particular documentation to future maintainers. We should do better there!

64kB is the least magic of the magic numbers because it has some reality in the UDP wire protocol. 2kB is the next least magic because it has some reality in the ethernet wire protocol, which is often relevant.

I really appreciate the help @lukasa. Thank you.

1 Like