UdpSendStatus SendFragmentedMessage(UdpRawMessage message, IChannel channel) { message.Position = 0; int mtu = this.Mtu; ushort frame = 1; ushort frames = (ushort)Math.Ceiling(message.Length / (float)(mtu - Datagram.GetHeaderSize(true))); ushort groupId = GetNextFragementationGroupId(); do { Debug.Assert(frame <= frames, "frame > frames"); Datagram datagramFrag = Datagram.CreateNew(peer.Configuration.MemoryStreamPool, mtu); datagramFrag.Type = MessageType.UserData; datagramFrag.Channel = channel.Descriptor.Channel; datagramFrag.DeliveryType = channel.Descriptor.DeliveryType; datagramFrag.FragmentationInfo = new Datagram.FragmentInfo(groupId, frame, frames); datagramFrag.ConnectionKey = this.EndPoint.ConnectionKey; int toCopy = mtu - Datagram.GetHeaderSize(true); if (toCopy > message.Length - message.Position) { toCopy = message.Length - message.Position; } message.CopyTo(datagramFrag.BaseStream, toCopy); channel.SendDatagram(datagramFrag); frame++; } while (message.Position < message.Length); message.Dispose(); return(UdpSendStatus.Enqueued); }
bool CheckCanBeSendUnfragmented(UdpRawMessage datagram) { if (datagram.Length + Datagram.GetHeaderSize(false) > Mtu) { return(false); } return(true); }
void SendNextMtuExpand() { int nextMtu = 0; if (smallestFailedMtu < 0) { nextMtu = (int)(this.Mtu * 1.25); } else { nextMtu = (int)(((float)smallestFailedMtu + (float)Mtu) / 2.0f); } if (nextMtu > peer.Configuration.LimitMtu) { nextMtu = peer.Configuration.LimitMtu; } if (nextMtu == Mtu) { FixMtu(); return; } lastMtuExpandSent = DateTime.UtcNow; int size = nextMtu - Datagram.GetHeaderSize(false); var mtuDatagram = CreateSpecialDatagram(MessageType.ExpandMTURequest, size); mtuDatagram.BaseStream.SetLength(size); if (mtuDatagram.GetTotalSize() != nextMtu) { throw new Exception("Datagram total size doesn't match header+body size. Perhaps header size calculation failed"); } logger.Debug($"Expanding MTU to {nextMtu}"); SendDatagramAsync(mtuDatagram).ContinueWith(t => { if (t.Result != System.Net.Sockets.SocketError.Success) { logger.Debug($"MTU {nextMtu} expand send failed with {t.Result}"); if (smallestFailedMtu < 1 || nextMtu < smallestFailedMtu) { smallestFailedMtu = nextMtu; mtuFailedAttempts++; if (mtuFailedAttempts >= peer.Configuration.MtuExpandMaxFailAttempts) { FixMtu(); return; } SendNextMtuExpand(); } } }, TaskContinuationOptions.OnlyOnRanToCompletion); }