diff --git a/Assets/NSM2/INetworkPacketHandler.cs b/Assets/NSM2/INetworkPacketHandler.cs index fa0ff30..de7c8a0 100644 --- a/Assets/NSM2/INetworkPacketHandler.cs +++ b/Assets/NSM2/INetworkPacketHandler.cs @@ -1,16 +1,30 @@ -// -// Copyright (c) Bytedance Inc 2021. All right reserved. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -using ByteDance.NAPI; +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ using System; using System.IO; @@ -37,7 +51,7 @@ public interface INetworkPacketHandler /// /// The user data(such as pb buffer) /// The pdu wrapped with c++ obstream*) for Encode output - void EncodePDU(int cmd, NativeDataView ud, IntPtr ob); + void EncodePDU(int cmd, Span ud, IntPtr ob); /// /// 处理应用层协议单元(协议头+PB数据) @@ -45,7 +59,7 @@ public interface INetworkPacketHandler /// The pointer of first byte of whole PDU /// The length of PDU /// - (int, NativeDataView,Stream) DecodePDU(IntPtr d, int len); + (int, Stream) DecodePDU(IntPtr d, int len, out Span msg); /// /// 处理网络事件 @@ -54,6 +68,6 @@ public interface INetworkPacketHandler /// 消息码 /// 消息 /// 信道 - void HandleEvent(NetworkEvent ev, int cmd, NativeDataView ud, int channel); + void HandleEvent(NetworkEvent ev, int cmd, Span ud, int channel); } } diff --git a/Assets/NSM2/NetworkServiceManager.cs b/Assets/NSM2/NetworkServiceManager.cs index df70f45..9da57f5 100644 --- a/Assets/NSM2/NetworkServiceManager.cs +++ b/Assets/NSM2/NetworkServiceManager.cs @@ -1,19 +1,34 @@ -// -// Copyright (c) Bytedance Inc 2021. All right reserved. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ using System; using System.Collections.Generic; using UnityEngine; using AOT; -using ByteDance.NAPI; using System.IO; namespace NSM2 @@ -215,10 +230,10 @@ void BroadcastEventToListeners(NetworkEventType eventType, int ec, int channel = } } - unsafe public void SendSerializedMsg(int cmd, NativeDataView ud, int channel = 0) + unsafe public void SendSerializedMsg(int cmd, Span ud, int channel = 0) { // The whole packet is sizeof(body) + sizeof(header), so no memory realloc - IntPtr pdu = YASIO_NI.yasio_ob_new(ud.len + _packeter.GetHeaderSize()); + IntPtr pdu = YASIO_NI.yasio_ob_new(ud.Length + _packeter.GetHeaderSize()); _packeter.EncodePDU(cmd, ud, pdu); if (channel < _sessions.Length) @@ -246,15 +261,16 @@ unsafe public void SendSerializedMsg(int cmd, NativeDataView ud, int channel = 0 /// 向远端发送数据 /// /// - public void SendRaw(NativeDataView data, int channel) + public unsafe void SendRaw(Span data, int channel) { if (channel < _sessions.Length) { IntPtr sid = _sessions[channel]; if (sid != IntPtr.Zero) { - - YASIO_NI.yasio_write(_service, sid, data.ptr, data.len); + fixed (void* p = data) { + YASIO_NI.yasio_write(_service, sid, (IntPtr)p, data.Length); + } } else { @@ -270,10 +286,7 @@ public void SendRaw(NativeDataView data, int channel) public unsafe void SendRaw(byte[] data, int channel) { - fixed (byte* p = data) - { - SendRaw(new NativeDataView((IntPtr)p, data.Length), channel); - } + SendRaw(new Span(data), channel); } /// @@ -312,34 +325,35 @@ static void HandleNativeConsolePrint(int level, string msg) /// /// The stack address of shared_ptr [MonoPInvokeCallback(typeof(YASIO_NI.YNIEventDelegate))] - static void HandleNativeNetworkIoEvent(ref YASIO_NI.EventData data) + static void HandleNativeNetworkIoEvent(ref YASIO_NI.IOEvent ev) { var nsm = NetworkServiceManager.Instance; - Debug.LogFormat("The channel connect_id={0}, bytes_transferred={1}", YASIO_NI.yasio_connect_id(nsm._service, data.channel), - YASIO_NI.yasio_bytes_transferred(nsm._service, data.channel)); - switch ((YASIO_NI.YEnums)data.kind) + Debug.LogFormat("The channel connect_id={0}, bytes_transferred={1}", YASIO_NI.yasio_connect_id(nsm._service, ev.channel), + YASIO_NI.yasio_bytes_transferred(nsm._service, ev.channel)); + switch ((YASIO_NI.YEnums)ev.kind) { case YASIO_NI.YEnums.YEK_ON_PACKET: - (int cmd, NativeDataView ud, Stream hold) = nsm._packeter.DecodePDU(YASIO_NI.yasio_unwrap_ptr(data.packet, 0), YASIO_NI.yasio_unwrap_len(data.packet, 0)); - nsm._packeter.HandleEvent(NetworkEvent.PACKET, cmd, ud, data.channel); + Span ud; + (int cmd, Stream hold) = nsm._packeter.DecodePDU(YASIO_NI.yasio_unwrap_ptr(ev.data.msg, 0), YASIO_NI.yasio_unwrap_len(ev.data.msg, 0), out ud); + nsm._packeter.HandleEvent(NetworkEvent.PACKET, cmd, ud, ev.channel); hold?.Dispose(); break; case YASIO_NI.YEnums.YEK_ON_OPEN: - if (data.status == 0) + if (ev.data.error == 0) { - nsm.UpdateSession(data.channel, data.session); - nsm.BroadcastEventToListeners(NetworkEventType.CONNECT_SUCCESS, 0, data.channel); - nsm._packeter.HandleEvent(NetworkEvent.CONNECT_SUCCESS, -1, NativeDataView.NullValue, data.channel); + nsm.UpdateSession(ev.channel, ev.thandle); + nsm.BroadcastEventToListeners(NetworkEventType.CONNECT_SUCCESS, 0, ev.channel); + nsm._packeter.HandleEvent(NetworkEvent.CONNECT_SUCCESS, -1, Span.Empty, ev.channel); } else { - nsm.BroadcastEventToListeners(NetworkEventType.CONNECT_FAILED, data.status, data.channel); - nsm._packeter.HandleEvent(NetworkEvent.CONNECT_FAILED, -1, NativeDataView.NullValue, data.channel); + nsm.BroadcastEventToListeners(NetworkEventType.CONNECT_FAILED, ev.data.error, ev.channel); + nsm._packeter.HandleEvent(NetworkEvent.CONNECT_FAILED, -1, Span.Empty, ev.channel); } break; case YASIO_NI.YEnums.YEK_ON_CLOSE: - nsm.BroadcastEventToListeners(NetworkEventType.CONNECTION_LOST, data.status, data.channel); - nsm._packeter.HandleEvent(NetworkEvent.CONNECTION_LOST, -1, NativeDataView.NullValue, data.channel); + nsm.BroadcastEventToListeners(NetworkEventType.CONNECTION_LOST, ev.data.error, ev.channel); + nsm._packeter.HandleEvent(NetworkEvent.CONNECTION_LOST, -1, Span.Empty, ev.channel); break; } } diff --git a/Assets/NSM2/Singleton.cs b/Assets/NSM2/Singleton.cs index 8e57a10..2a7fc2b 100644 --- a/Assets/NSM2/Singleton.cs +++ b/Assets/NSM2/Singleton.cs @@ -1,14 +1,30 @@ -// -// Copyright (c) Bytedance Inc 2021. All right reserved. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ using System; using UnityEngine; diff --git a/Assets/NSM2/YASIO_NI.cs b/Assets/NSM2/YASIO_NI.cs index 60764c0..c1e1d0c 100644 --- a/Assets/NSM2/YASIO_NI.cs +++ b/Assets/NSM2/YASIO_NI.cs @@ -1,16 +1,32 @@ -// -// Copyright (c) Bytedance Inc 2021-2022. All right reserved. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -/* Match with yasio-4.0.x+ */ +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/* Match with yasio-5.0.x+ */ using System; using System.Runtime.InteropServices; @@ -23,21 +39,28 @@ public class YASIO_NI #else public const string LIBNAME = "yasio"; #endif - // match with yasio/binding/yasio_ni.cpp: struct yasio_event_data + // match with yasio/binding/yasio_ni.cpp: struct yasio_io_event [StructLayout(LayoutKind.Sequential)] - public unsafe struct EventData + public unsafe struct IOEvent { public int kind; - public int status; public int channel; - public IntPtr session; // transport - public IntPtr packet; - public IntPtr user; // the user data + public IntPtr thandle; - public static readonly int cbSize = sizeof(EventData); + [StructLayout(LayoutKind.Explicit)] + public unsafe struct EventData + { + [FieldOffset(0)] public IntPtr msg; + [FieldOffset(0)] public int error; + } + + public EventData data; + public void* user; + + public static readonly int cbSize = sizeof(IOEvent); } - public delegate void YNIEventDelegate(ref EventData eventData); + public delegate void YNIEventDelegate(ref IOEvent eventData); public delegate int YNIResolvDelegate(string host, IntPtr sbuf); public delegate void YNIPrintDelegate(int level, string msg); diff --git a/Assets/Plugins/x86_64/yasio.dll b/Assets/Plugins/x86_64/yasio.dll index f1889ec..7699dfa 100644 Binary files a/Assets/Plugins/x86_64/yasio.dll and b/Assets/Plugins/x86_64/yasio.dll differ diff --git a/Assets/Scripts/AppProtocol.cs b/Assets/Scripts/AppProtocol.cs index 340279d..0fac028 100644 --- a/Assets/Scripts/AppProtocol.cs +++ b/Assets/Scripts/AppProtocol.cs @@ -1,15 +1,30 @@ -// -// Copyright (c) Bytedance Inc 2021. All right reserved. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -using ByteDance.NAPI; +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ using System; using System.IO; using System.Net; @@ -29,73 +44,90 @@ public class AppProtocol public const short CMD_LOGIN_REQ = 2021; public const int CMD_LOGIN_RESP = 2022; - public interface Message + public abstract class Message { - void print(); - unsafe (NativeDataView, Stream) encode(); - unsafe void decode(NativeDataView ud); + public virtual void print() { } + public virtual Span encode() { return null; } + public virtual unsafe void decode(Span ud) { } + + protected BinaryWriter m_writer = null; + + public BinaryWriter writer() { + if (m_writer != null) m_writer.Dispose(); + return new BinaryWriter(new MemoryStream()); + } + + public void Dispose() + { + if(m_writer != null) m_writer.Dispose(); + m_writer = null; + } } + public class LoginReq : Message { public int uid = 0; - public void print() + public override void print() { UnityEngine.Debug.LogFormat("---> LoginReq: \r\n uid={0}", uid); } - public unsafe (NativeDataView, Stream) encode() + public override unsafe Span encode() { - MemoryStream ms = new MemoryStream(); - var writer = new BinaryWriter(ms); - writer.Write(IPAddress.HostToNetworkOrder(uid)); + var w = writer(); + + w.Write(IPAddress.HostToNetworkOrder(uid)); + + var ms = (MemoryStream)w.BaseStream; var buf = ms.GetBuffer(); - fixed (byte* data = buf) - { - return (new NativeDataView((IntPtr)data, (int)ms.Length), ms); - } + return new Span(buf, 0, (int)ms.Length); } - public unsafe void decode(NativeDataView ud) + public override unsafe void decode(Span ud) { - using (UnmanagedMemoryStream ums = new UnmanagedMemoryStream((byte*)ud.ptr, ud.len)) + fixed(byte* ptr = ud) { - BinaryReader reader = new BinaryReader(ums); - uid = IPAddress.NetworkToHostOrder(reader.ReadInt32()); - reader.Dispose(); + using (UnmanagedMemoryStream ums = new UnmanagedMemoryStream(ptr, ud.Length)) + { + BinaryReader reader = new BinaryReader(ums); + uid = IPAddress.NetworkToHostOrder(reader.ReadInt32()); + reader.Dispose(); + } } } } - public class LoginResp + public class LoginResp : Message { - public void print() + public override void print() { UnityEngine.Debug.LogFormat("---> LoginResp: \r\n uid={0}, status={1}", uid, status); } - public unsafe (NativeDataView, Stream) encode() + public override unsafe Span encode() { - MemoryStream ms = new MemoryStream(); - - var writer = new BinaryWriter(ms); - writer.Write(IPAddress.HostToNetworkOrder(uid)); - writer.Write(IPAddress.HostToNetworkOrder(status)); + var w = writer(); + + w.Write(IPAddress.HostToNetworkOrder(uid)); + w.Write(IPAddress.HostToNetworkOrder(status)); + + var ms = (MemoryStream)w.BaseStream; var buf = ms.GetBuffer(); - fixed (byte* data = buf) - { - return (new NativeDataView((IntPtr)data, (int)ms.Length), ms); - } + return new Span(buf, 0, (int)ms.Length); } - public unsafe void decode(NativeDataView ud) + public override unsafe void decode(Span ud) { - using (UnmanagedMemoryStream ums = new UnmanagedMemoryStream((byte*)ud.ptr, ud.len)) + fixed (byte* ptr = ud) { - BinaryReader reader = new BinaryReader(ums); - uid = IPAddress.NetworkToHostOrder(reader.ReadInt32()); - status = IPAddress.NetworkToHostOrder(reader.ReadInt32()); - reader.Dispose(); + using (UnmanagedMemoryStream ums = new UnmanagedMemoryStream(ptr, ud.Length)) + { + BinaryReader reader = new BinaryReader(ums); + uid = IPAddress.NetworkToHostOrder(reader.ReadInt32()); + status = IPAddress.NetworkToHostOrder(reader.ReadInt32()); + reader.Dispose(); + } } } public int uid; diff --git a/Assets/Scripts/SampleNetworkPacketHandler.cs b/Assets/Scripts/SampleNetworkPacketHandler.cs index 7da5b5b..cb92647 100644 --- a/Assets/Scripts/SampleNetworkPacketHandler.cs +++ b/Assets/Scripts/SampleNetworkPacketHandler.cs @@ -1,15 +1,30 @@ -// -// Copyright (c) Bytedance Inc 2021. All right reserved. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -using ByteDance.NAPI; +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ using System; using System.IO; using System.Net; @@ -49,15 +64,18 @@ public int GetHeaderSize() return PROTO_HEADER_SIZE; } - unsafe public void EncodePDU(int cmd, NativeDataView ud, IntPtr ob) + unsafe public void EncodePDU(int cmd, Span ud, IntPtr ob) { YASIO_NI.yasio_ob_write_short(ob, (short)cmd); - YASIO_NI.yasio_ob_write_int(ob, ud.len); // packet size + YASIO_NI.yasio_ob_write_int(ob, ud.Length); // packet size YASIO_NI.yasio_ob_write_int(ob, VERIFIED_MAGIC_NUM); // magic number - YASIO_NI.yasio_ob_write_bytes(ob, ud.ptr, ud.len); // ud + fixed (void* bytes = ud) + { + YASIO_NI.yasio_ob_write_bytes(ob, (IntPtr)bytes, ud.Length); // ud + } } - unsafe public (int, NativeDataView, Stream) DecodePDU(IntPtr bytes, int len) + unsafe public (int, Stream) DecodePDU(IntPtr bytes, int len, out Span msg) { Stream dataStream = new UnmanagedMemoryStream((byte*)bytes, len); try @@ -77,15 +95,13 @@ unsafe public (int, NativeDataView, Stream) DecodePDU(IntPtr bytes, int len) if (DUMP_RECV_HEX) { int bodyLen = len - PROTO_HEADER_SIZE; // the udLen===bodyLen - string wholeHexs = YASIO_NI.DumpHex(bytes, len); - UnityEngine.Debug.LogFormat("cmd={0}, udLen/bodyLen={1}/{2}, wholeHexs: {3}\n", cmd, udLen, bodyLen, wholeHexs); - string bodyHexs = YASIO_NI.DumpHex(bytes + PROTO_HEADER_SIZE, bodyLen); - UnityEngine.Debug.LogFormat("cmd={0}, bodyHexs: {1}\n", cmd, bodyHexs); + UnityEngine.Debug.LogFormat("cmd={0}, udLen/bodyLen={1}/{2}, msg: {3}\n", cmd, udLen, bodyLen, YASIO_NI.DumpHex(bytes, len)); + UnityEngine.Debug.LogFormat("cmd={0}, payload: {1}\n", cmd, YASIO_NI.DumpHex(bytes + PROTO_HEADER_SIZE, bodyLen)); } #endif - NativeDataView ud = new NativeDataView { ptr = bytes + PROTO_HEADER_SIZE, len = len - PROTO_HEADER_SIZE }; + msg = new Span((bytes + PROTO_HEADER_SIZE).ToPointer(), len - PROTO_HEADER_SIZE); - return (cmd, ud, dataStream); + return (cmd, dataStream); } else { @@ -98,7 +114,8 @@ unsafe public (int, NativeDataView, Stream) DecodePDU(IntPtr bytes, int len) dataStream?.Dispose(); } - return (-1, NativeDataView.NullValue, null); + msg = Span.Empty; + return (-1, null); } /// @@ -108,7 +125,7 @@ unsafe public (int, NativeDataView, Stream) DecodePDU(IntPtr bytes, int len) /// /// /// - public void HandleEvent(NetworkEvent ev, int cmd, NativeDataView ud, int channel) + public void HandleEvent(NetworkEvent ev, int cmd, Span ud, int channel) { UnityEngine.Debug.LogFormat("SampleNetworkPacketHandler.HandleEvent, event={0}, cmd={1}, channel={2}", ev, cmd, channel); if(cmd == AppProtocol.CMD_LOGIN_REQ) @@ -121,9 +138,8 @@ public void HandleEvent(NetworkEvent ev, int cmd, NativeDataView ud, int channel var reply = new AppProtocol.LoginResp(); reply.uid = msg.uid; reply.status = 200; // 200 表示success - (NativeDataView udReply, Stream hold) = reply.encode(); + Span udReply = reply.encode(); NetworkServiceManager.Instance.SendSerializedMsg(AppProtocol.CMD_LOGIN_RESP, udReply, AppProtocol.SERVER_CHANNEL); - hold.Dispose(); } else if(cmd == AppProtocol.CMD_LOGIN_RESP) { // SampelScene应该是 channel:0 收到 diff --git a/Assets/Scripts/SampleScene.cs b/Assets/Scripts/SampleScene.cs index 7328dcc..c949093 100644 --- a/Assets/Scripts/SampleScene.cs +++ b/Assets/Scripts/SampleScene.cs @@ -1,14 +1,30 @@ -// -// Copyright (c) Bytedance Inc 2021. All right reserved. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ using UnityEngine; using NSM2; using System; @@ -56,11 +72,11 @@ unsafe public void OnConnectSuccess(int channel = 0) // 模拟登录协议 var loginReq = new AppProtocol.LoginReq(); loginReq.uid = 1219; - (var ud, var ms) = loginReq.encode(); + Span ud = loginReq.encode(); nsm.SendSerializedMsg(AppProtocol.CMD_LOGIN_REQ, ud, AppProtocol.CLIENT_CHANNEL); - ms.Dispose(); + loginReq.Dispose(); } else if(channel == AppProtocol.SERVER_CHANNEL) { diff --git a/LocalPackages/com.bytedance.napi/ByteDance.NAPI.asmdef b/LocalPackages/com.bytedance.napi/ByteDance.NAPI.asmdef deleted file mode 100644 index 5c4f5f5..0000000 --- a/LocalPackages/com.bytedance.napi/ByteDance.NAPI.asmdef +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "ByteDance.NAPI", - "references": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": true -} \ No newline at end of file diff --git a/LocalPackages/com.bytedance.napi/ByteDance.NAPI.asmdef.meta b/LocalPackages/com.bytedance.napi/ByteDance.NAPI.asmdef.meta deleted file mode 100644 index 7aae9e9..0000000 --- a/LocalPackages/com.bytedance.napi/ByteDance.NAPI.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5d7149410a8a1a34097bd36a18dbf316 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/LocalPackages/com.bytedance.napi/NativeDataTypes.cs b/LocalPackages/com.bytedance.napi/NativeDataTypes.cs deleted file mode 100644 index d645fdc..0000000 --- a/LocalPackages/com.bytedance.napi/NativeDataTypes.cs +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) Bytedance Inc 2021. All right reserved. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -using System; - -namespace ByteDance.NAPI -{ - /// - /// Could use as Natvie CStr or byte array - /// - public struct NativeDataView - { - public IntPtr ptr; - public int len; - - public NativeDataView(IntPtr p, int l) - { - ptr = p; - len = l; - } - - public void Set(IntPtr p, int l) - { - ptr = p; - len = l; - } - - public bool IsNull() - { - return ptr == IntPtr.Zero; - } - - public void SetNull() - { - ptr = IntPtr.Zero; - len = 0; - } - - public bool IsEmpty() - { - return ptr == IntPtr.Zero || len == 0; - } - - public static readonly NativeDataView NullValue = new NativeDataView(IntPtr.Zero, 0); - } - - /// - /// Could use as any natvie UDT* view, not char* - /// Such as Lua TString* - /// - public struct NativeUDTView - { - public NativeUDTView(IntPtr p) - { - ptr = p; - } - - public bool IsNull() - { - return ptr == IntPtr.Zero; - } - - public void Set(IntPtr p) - { - ptr = p; - } - - public IntPtr ptr; // the lua vm TString* - - public static readonly NativeUDTView NullValue = new NativeUDTView(IntPtr.Zero); - } -} diff --git a/LocalPackages/com.bytedance.napi/NativeDataTypes.cs.meta b/LocalPackages/com.bytedance.napi/NativeDataTypes.cs.meta deleted file mode 100644 index 23d885a..0000000 --- a/LocalPackages/com.bytedance.napi/NativeDataTypes.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8501494195697ce4e85aae685c4b05dc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/LocalPackages/com.bytedance.napi/README.md b/LocalPackages/com.bytedance.napi/README.md deleted file mode 100644 index 6741e21..0000000 --- a/LocalPackages/com.bytedance.napi/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# ByteDance.NAPI - -方便和Native数据指针交互的通用数据结构 \ No newline at end of file diff --git a/LocalPackages/com.bytedance.napi/README.md.meta b/LocalPackages/com.bytedance.napi/README.md.meta deleted file mode 100644 index c7d5a42..0000000 --- a/LocalPackages/com.bytedance.napi/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5695b22997f20b5499ba6bfcd9dfe3e5 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/LocalPackages/com.bytedance.napi/package.json b/LocalPackages/com.bytedance.napi/package.json deleted file mode 100644 index 2187672..0000000 --- a/LocalPackages/com.bytedance.napi/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "com.bytedance.napi", - "displayName": "ByteDance NAPI", - "version": "1.0.0", - "unity": "2019.2", - "keywords": ["ByteDance", "NAPI"], - "description": "ByteDance Native API for interop.", - "dependencies": { - } -} \ No newline at end of file diff --git a/LocalPackages/com.bytedance.napi/package.json.meta b/LocalPackages/com.bytedance.napi/package.json.meta deleted file mode 100644 index 109d96c..0000000 --- a/LocalPackages/com.bytedance.napi/package.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 4952efaa7b7e1e3478648467e1ea647c -PackageManifestImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/NativeLibs/yasio/1k/fetch.cmake b/NativeLibs/yasio/1k/fetch.cmake new file mode 100644 index 0000000..391bb53 --- /dev/null +++ b/NativeLibs/yasio/1k/fetch.cmake @@ -0,0 +1,76 @@ +# +# the 1k fetch functions +# require predefine variable: +# _1kfetch_cache_dir +# _1kfetch_manifest +# + +### 1kdist url +find_program(PWSH_COMMAND NAMES pwsh powershell NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH) + +function(_1kfetch_init) + execute_process(COMMAND ${PWSH_COMMAND} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/fetchurl.ps1 + -name "1kdist" + -cfg ${_1kfetch_manifest} + OUTPUT_VARIABLE _1kdist_url + ) + string(REPLACE "#" ";" _1kdist_url ${_1kdist_url}) + list(GET _1kdist_url 0 _1kdist_base_url) + list(GET _1kdist_url 1 _1kdist_ver) + set(_1kdist_base_url "${_1kdist_base_url}/v${_1kdist_ver}" PARENT_SCOPE) + set(_1kdist_ver ${_1kdist_ver} PARENT_SCOPE) +endfunction() + +# fetch prebuilt from 1kdist +# param package_name +function(_1kfetch_dist package_name) + set(_prebuilt_root ${CMAKE_CURRENT_LIST_DIR}/_d) + if(NOT IS_DIRECTORY ${_prebuilt_root}) + set (package_store "${_1kfetch_cache_dir}/1kdist/v${_1kdist_ver}/${package_name}.zip") + if (NOT EXISTS ${package_store}) + set (package_url "${_1kdist_base_url}/${package_name}.zip") + message(AUTHOR_WARNING "Downloading ${package_url}") + file(DOWNLOAD ${package_url} ${package_store} STATUS _status LOG _logs SHOW_PROGRESS) + list(GET _status 0 status_code) + list(GET _status 1 status_string) + if(NOT status_code EQUAL 0) + message(FATAL_ERROR "Download ${package_url} fail, ${status_string}, logs: ${_logs}") + endif() + endif() + file(ARCHIVE_EXTRACT INPUT ${package_store} DESTINATION ${CMAKE_CURRENT_LIST_DIR}/) + file(RENAME ${CMAKE_CURRENT_LIST_DIR}/${package_name} ${_prebuilt_root}) + endif() + + # set platform specific path, PLATFORM_NAME provided by user: win32,winrt,mac,ios,android,tvos,watchos,linux + set(_prebuilt_lib_dir "${_prebuilt_root}/lib/${PLATFORM_NAME}") + if(ANDROID OR WIN32) + set(_prebuilt_lib_dir "${_prebuilt_lib_dir}/${ARCH_ALIAS}") + endif() + set(${package_name}_INC_DIR ${_prebuilt_root}/include PARENT_SCOPE) + set(${package_name}_LIB_DIR ${_prebuilt_lib_dir} PARENT_SCOPE) +endfunction() + +# params: name, url +function(_1kfetch name) + set(_pkg_store "${_1kfetch_cache_dir}/${name}") + execute_process(COMMAND ${PWSH_COMMAND} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/fetch.ps1 + -name "${name}" + -dest "${_pkg_store}" + -cfg ${_1kfetch_manifest} + RESULT_VARIABLE _errorcode + ) + if (_errorcode) + message(FATAL_ERROR "aborted") + endif() + set(${name}_SOURCE_DIR ${_pkg_store} PARENT_SCOPE) +endfunction() + +function(_1klink src dest) + file(TO_NATIVE_PATH "${src}" _srcDir) + file(TO_NATIVE_PATH "${dest}" _dstDir) + execute_process(COMMAND ${PWSH_COMMAND} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/fsync.ps1 -s "${_srcDir}" -d "${_dstDir}" -l 1) +endfunction() + +if(PWSH_COMMAND) + _1kfetch_init() +endif() diff --git a/NativeLibs/yasio/1k/fetchurl.ps1 b/NativeLibs/yasio/1k/fetchurl.ps1 new file mode 100644 index 0000000..4a3d857 --- /dev/null +++ b/NativeLibs/yasio/1k/fetchurl.ps1 @@ -0,0 +1,13 @@ +param( + $name, + $cfg +) + +$mirror = if (!(Test-Path (Join-Path $PSScriptRoot '.gitee') -PathType Leaf)) {'github'} else {'gitee'} +$url_base = @{'github' = 'https://github.com/'; 'gitee' = 'https://gitee.com/' }[$mirror] + +$manifest_map = ConvertFrom-Json (Get-Content $cfg -raw) +$ver = $manifest_map.versions.PSObject.Properties[$name].Value +$url_path = $manifest_map.mirrors.PSObject.Properties[$mirror].Value.PSObject.Properties[$name].Value + +Write-Host "$url_base$url_path#$ver" -NoNewline \ No newline at end of file diff --git a/NativeLibs/yasio/1k/platform.cmake b/NativeLibs/yasio/1k/platform.cmake new file mode 100644 index 0000000..b51f824 --- /dev/null +++ b/NativeLibs/yasio/1k/platform.cmake @@ -0,0 +1,76 @@ +#Please use them everywhere +#WINDOWS = Windows Desktop +#ANDROID = Android +#IOS = iOS +#MACOSX = MacOS X +#LINUX = Linux + +############################# +# cmake commands: +# win32: cmake -B build -A x64 +# winrt: cmake -B build -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" +# + +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(WINDOWS TRUE) + if("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "Win32") + set(WIN32 TRUE) + set(ARCH_ALIAS "x86") + elseif("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "arm64") + set(WIN64 TRUE) + set(ARCH_ALIAS "arm64") + else() + set(WIN64 TRUE) + set(ARCH_ALIAS "x64") + endif() + set(PLATFORM_NAME win32) + if (${CMAKE_SYSTEM_NAME} MATCHES "WindowsStore") + set(WINRT TRUE CACHE BOOL "" FORCE) + set(PLATFORM_NAME winrt) + endif() +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Android") + set(PLATFORM_NAME android) + set(ARCH_ALIAS ${ANDROID_ABI}) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(LINUX TRUE) + set(PLATFORM_NAME linux) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") + set(WASM TRUE) + set(EMSCRIPTEN TRUE) + set(PLATFORM_NAME wasm) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(APPLE TRUE) + set(MACOSX TRUE) + set(PLATFORM_NAME mac) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "iOS") + set(APPLE TRUE) + set(IOS TRUE) + set(PLATFORM_NAME ios) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "tvOS") + set(APPLE TRUE) + set(IOS TRUE) + set(TVOS TRUE) + set(PLATFORM_NAME tvos) +else() + message(AUTHOR_WARNING "Unsupported platform to use prebuilt libs") + return() +endif() + +if (NOT DEFINED WIN32) + set(WIN32 FALSE) +endif() + +# generators that are capable of organizing into a hierarchy of folders +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +# simplify generator condition, please use them everywhere +if(CMAKE_GENERATOR STREQUAL Xcode) + set(XCODE TRUE) +elseif(CMAKE_GENERATOR MATCHES Visual) + set(VS TRUE) +endif() + +function(_1k_deprecated_32bit project_name release_ver) + if(("${ARCH_ALIAS}" STREQUAL "x86") OR ("${ARCH_ALIAS}" MATCHES "armeabi-v7a")) + message(WARNING "Building 32-bit[${ARCH_ALIAS}] ${project_name} is deprecated, and will be removed in next release ${release_ver}") + endif() +endfunction() diff --git a/NativeLibs/yasio/kcp/ikcp.c b/NativeLibs/yasio/3rdparty/kcp/ikcp.c similarity index 96% rename from NativeLibs/yasio/kcp/ikcp.c rename to NativeLibs/yasio/3rdparty/kcp/ikcp.c index 8070a78..6e14bc9 100644 --- a/NativeLibs/yasio/kcp/ikcp.c +++ b/NativeLibs/yasio/3rdparty/kcp/ikcp.c @@ -1,1306 +1,1306 @@ -//===================================================================== -// -// KCP - A Better ARQ Protocol Implementation -// skywind3000 (at) gmail.com, 2010-2011 -// -// Features: -// + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. -// + Maximum RTT reduce three times vs tcp. -// + Lightweight, distributed as a single source file. -// -//===================================================================== -#include "ikcp.h" - -#include -#include -#include -#include -#include - - - -//===================================================================== -// KCP BASIC -//===================================================================== -const IUINT32 IKCP_RTO_NDL = 30; // no delay min rto -const IUINT32 IKCP_RTO_MIN = 100; // normal min rto -const IUINT32 IKCP_RTO_DEF = 200; -const IUINT32 IKCP_RTO_MAX = 60000; -const IUINT32 IKCP_CMD_PUSH = 81; // cmd: push data -const IUINT32 IKCP_CMD_ACK = 82; // cmd: ack -const IUINT32 IKCP_CMD_WASK = 83; // cmd: window probe (ask) -const IUINT32 IKCP_CMD_WINS = 84; // cmd: window size (tell) -const IUINT32 IKCP_ASK_SEND = 1; // need to send IKCP_CMD_WASK -const IUINT32 IKCP_ASK_TELL = 2; // need to send IKCP_CMD_WINS -const IUINT32 IKCP_WND_SND = 32; -const IUINT32 IKCP_WND_RCV = 128; // must >= max fragment size -const IUINT32 IKCP_MTU_DEF = 1400; -const IUINT32 IKCP_ACK_FAST = 3; -const IUINT32 IKCP_INTERVAL = 100; -const IUINT32 IKCP_OVERHEAD = 24; -const IUINT32 IKCP_DEADLINK = 20; -const IUINT32 IKCP_THRESH_INIT = 2; -const IUINT32 IKCP_THRESH_MIN = 2; -const IUINT32 IKCP_PROBE_INIT = 7000; // 7 secs to probe window size -const IUINT32 IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window -const IUINT32 IKCP_FASTACK_LIMIT = 5; // max times to trigger fastack - - -//--------------------------------------------------------------------- -// encode / decode -//--------------------------------------------------------------------- - -/* encode 8 bits unsigned int */ -static inline char *ikcp_encode8u(char *p, unsigned char c) -{ - *(unsigned char*)p++ = c; - return p; -} - -/* decode 8 bits unsigned int */ -static inline const char *ikcp_decode8u(const char *p, unsigned char *c) -{ - *c = *(unsigned char*)p++; - return p; -} - -/* encode 16 bits unsigned int (lsb) */ -static inline char *ikcp_encode16u(char *p, unsigned short w) -{ -#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN - *(unsigned char*)(p + 0) = (w & 255); - *(unsigned char*)(p + 1) = (w >> 8); -#else - memcpy(p, &w, 2); -#endif - p += 2; - return p; -} - -/* decode 16 bits unsigned int (lsb) */ -static inline const char *ikcp_decode16u(const char *p, unsigned short *w) -{ -#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN - *w = *(const unsigned char*)(p + 1); - *w = *(const unsigned char*)(p + 0) + (*w << 8); -#else - memcpy(w, p, 2); -#endif - p += 2; - return p; -} - -/* encode 32 bits unsigned int (lsb) */ -static inline char *ikcp_encode32u(char *p, IUINT32 l) -{ -#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN - *(unsigned char*)(p + 0) = (unsigned char)((l >> 0) & 0xff); - *(unsigned char*)(p + 1) = (unsigned char)((l >> 8) & 0xff); - *(unsigned char*)(p + 2) = (unsigned char)((l >> 16) & 0xff); - *(unsigned char*)(p + 3) = (unsigned char)((l >> 24) & 0xff); -#else - memcpy(p, &l, 4); -#endif - p += 4; - return p; -} - -/* decode 32 bits unsigned int (lsb) */ -static inline const char *ikcp_decode32u(const char *p, IUINT32 *l) -{ -#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN - *l = *(const unsigned char*)(p + 3); - *l = *(const unsigned char*)(p + 2) + (*l << 8); - *l = *(const unsigned char*)(p + 1) + (*l << 8); - *l = *(const unsigned char*)(p + 0) + (*l << 8); -#else - memcpy(l, p, 4); -#endif - p += 4; - return p; -} - -static inline IUINT32 _imin_(IUINT32 a, IUINT32 b) { - return a <= b ? a : b; -} - -static inline IUINT32 _imax_(IUINT32 a, IUINT32 b) { - return a >= b ? a : b; -} - -static inline IUINT32 _ibound_(IUINT32 lower, IUINT32 middle, IUINT32 upper) -{ - return _imin_(_imax_(lower, middle), upper); -} - -static inline long _itimediff(IUINT32 later, IUINT32 earlier) -{ - return ((IINT32)(later - earlier)); -} - -//--------------------------------------------------------------------- -// manage segment -//--------------------------------------------------------------------- -typedef struct IKCPSEG IKCPSEG; - -static void* (*ikcp_malloc_hook)(size_t) = NULL; -static void (*ikcp_free_hook)(void *) = NULL; - -// internal malloc -static void* ikcp_malloc(size_t size) { - if (ikcp_malloc_hook) - return ikcp_malloc_hook(size); - return malloc(size); -} - -// internal free -static void ikcp_free(void *ptr) { - if (ikcp_free_hook) { - ikcp_free_hook(ptr); - } else { - free(ptr); - } -} - -// redefine allocator -void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)) -{ - ikcp_malloc_hook = new_malloc; - ikcp_free_hook = new_free; -} - -// allocate a new kcp segment -static IKCPSEG* ikcp_segment_new(ikcpcb *kcp, int size) -{ - return (IKCPSEG*)ikcp_malloc(sizeof(IKCPSEG) + size); -} - -// delete a segment -static void ikcp_segment_delete(ikcpcb *kcp, IKCPSEG *seg) -{ - ikcp_free(seg); -} - -// write log -void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...) -{ - char buffer[1024]; - va_list argptr; - if ((mask & kcp->logmask) == 0 || kcp->writelog == 0) return; - va_start(argptr, fmt); - vsprintf(buffer, fmt, argptr); - va_end(argptr); - kcp->writelog(buffer, kcp, kcp->user); -} - -// check log mask -static int ikcp_canlog(const ikcpcb *kcp, int mask) -{ - if ((mask & kcp->logmask) == 0 || kcp->writelog == NULL) return 0; - return 1; -} - -// output segment -static int ikcp_output(ikcpcb *kcp, const void *data, int size) -{ - assert(kcp); - assert(kcp->output); - if (ikcp_canlog(kcp, IKCP_LOG_OUTPUT)) { - ikcp_log(kcp, IKCP_LOG_OUTPUT, "[RO] %ld bytes", (long)size); - } - if (size == 0) return 0; - return kcp->output((const char*)data, size, kcp, kcp->user); -} - -// output queue -void ikcp_qprint(const char *name, const struct IQUEUEHEAD *head) -{ -#if 0 - const struct IQUEUEHEAD *p; - printf("<%s>: [", name); - for (p = head->next; p != head; p = p->next) { - const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); - printf("(%lu %d)", (unsigned long)seg->sn, (int)(seg->ts % 10000)); - if (p->next != head) printf(","); - } - printf("]\n"); -#endif -} - - -//--------------------------------------------------------------------- -// create a new kcpcb -//--------------------------------------------------------------------- -ikcpcb* ikcp_create(IUINT32 conv, void *user) -{ - ikcpcb *kcp = (ikcpcb*)ikcp_malloc(sizeof(struct IKCPCB)); - if (kcp == NULL) return NULL; - kcp->conv = conv; - kcp->user = user; - kcp->snd_una = 0; - kcp->snd_nxt = 0; - kcp->rcv_nxt = 0; - kcp->ts_recent = 0; - kcp->ts_lastack = 0; - kcp->ts_probe = 0; - kcp->probe_wait = 0; - kcp->snd_wnd = IKCP_WND_SND; - kcp->rcv_wnd = IKCP_WND_RCV; - kcp->rmt_wnd = IKCP_WND_RCV; - kcp->cwnd = 0; - kcp->incr = 0; - kcp->probe = 0; - kcp->mtu = IKCP_MTU_DEF; - kcp->mss = kcp->mtu - IKCP_OVERHEAD; - kcp->stream = 0; - - kcp->buffer = (char*)ikcp_malloc((kcp->mtu + IKCP_OVERHEAD) * 3); - if (kcp->buffer == NULL) { - ikcp_free(kcp); - return NULL; - } - - iqueue_init(&kcp->snd_queue); - iqueue_init(&kcp->rcv_queue); - iqueue_init(&kcp->snd_buf); - iqueue_init(&kcp->rcv_buf); - kcp->nrcv_buf = 0; - kcp->nsnd_buf = 0; - kcp->nrcv_que = 0; - kcp->nsnd_que = 0; - kcp->state = 0; - kcp->acklist = NULL; - kcp->ackblock = 0; - kcp->ackcount = 0; - kcp->rx_srtt = 0; - kcp->rx_rttval = 0; - kcp->rx_rto = IKCP_RTO_DEF; - kcp->rx_minrto = IKCP_RTO_MIN; - kcp->current = 0; - kcp->interval = IKCP_INTERVAL; - kcp->ts_flush = IKCP_INTERVAL; - kcp->nodelay = 0; - kcp->updated = 0; - kcp->logmask = 0; - kcp->ssthresh = IKCP_THRESH_INIT; - kcp->fastresend = 0; - kcp->fastlimit = IKCP_FASTACK_LIMIT; - kcp->nocwnd = 0; - kcp->xmit = 0; - kcp->dead_link = IKCP_DEADLINK; - kcp->output = NULL; - kcp->writelog = NULL; - - return kcp; -} - - -//--------------------------------------------------------------------- -// release a new kcpcb -//--------------------------------------------------------------------- -void ikcp_release(ikcpcb *kcp) -{ - assert(kcp); - if (kcp) { - IKCPSEG *seg; - while (!iqueue_is_empty(&kcp->snd_buf)) { - seg = iqueue_entry(kcp->snd_buf.next, IKCPSEG, node); - iqueue_del(&seg->node); - ikcp_segment_delete(kcp, seg); - } - while (!iqueue_is_empty(&kcp->rcv_buf)) { - seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); - iqueue_del(&seg->node); - ikcp_segment_delete(kcp, seg); - } - while (!iqueue_is_empty(&kcp->snd_queue)) { - seg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); - iqueue_del(&seg->node); - ikcp_segment_delete(kcp, seg); - } - while (!iqueue_is_empty(&kcp->rcv_queue)) { - seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); - iqueue_del(&seg->node); - ikcp_segment_delete(kcp, seg); - } - if (kcp->buffer) { - ikcp_free(kcp->buffer); - } - if (kcp->acklist) { - ikcp_free(kcp->acklist); - } - - kcp->nrcv_buf = 0; - kcp->nsnd_buf = 0; - kcp->nrcv_que = 0; - kcp->nsnd_que = 0; - kcp->ackcount = 0; - kcp->buffer = NULL; - kcp->acklist = NULL; - ikcp_free(kcp); - } -} - - -//--------------------------------------------------------------------- -// set output callback, which will be invoked by kcp -//--------------------------------------------------------------------- -void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, - ikcpcb *kcp, void *user)) -{ - kcp->output = output; -} - - -//--------------------------------------------------------------------- -// user/upper level recv: returns size, returns below zero for EAGAIN -//--------------------------------------------------------------------- -int ikcp_recv(ikcpcb *kcp, char *buffer, int len) -{ - struct IQUEUEHEAD *p; - int ispeek = (len < 0)? 1 : 0; - int peeksize; - int recover = 0; - IKCPSEG *seg; - assert(kcp); - - if (iqueue_is_empty(&kcp->rcv_queue)) - return -1; - - if (len < 0) len = -len; - - peeksize = ikcp_peeksize(kcp); - - if (peeksize < 0) - return -2; - - if (peeksize > len) - return -3; - - if (kcp->nrcv_que >= kcp->rcv_wnd) - recover = 1; - - // merge fragment - for (len = 0, p = kcp->rcv_queue.next; p != &kcp->rcv_queue; ) { - int fragment; - seg = iqueue_entry(p, IKCPSEG, node); - p = p->next; - - if (buffer) { - memcpy(buffer, seg->data, seg->len); - buffer += seg->len; - } - - len += seg->len; - fragment = seg->frg; - - if (ikcp_canlog(kcp, IKCP_LOG_RECV)) { - ikcp_log(kcp, IKCP_LOG_RECV, "recv sn=%lu", (unsigned long)seg->sn); - } - - if (ispeek == 0) { - iqueue_del(&seg->node); - ikcp_segment_delete(kcp, seg); - kcp->nrcv_que--; - } - - if (fragment == 0) - break; - } - - assert(len == peeksize); - - // move available data from rcv_buf -> rcv_queue - while (! iqueue_is_empty(&kcp->rcv_buf)) { - seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); - if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { - iqueue_del(&seg->node); - kcp->nrcv_buf--; - iqueue_add_tail(&seg->node, &kcp->rcv_queue); - kcp->nrcv_que++; - kcp->rcv_nxt++; - } else { - break; - } - } - - // fast recover - if (kcp->nrcv_que < kcp->rcv_wnd && recover) { - // ready to send back IKCP_CMD_WINS in ikcp_flush - // tell remote my window size - kcp->probe |= IKCP_ASK_TELL; - } - - return len; -} - - -//--------------------------------------------------------------------- -// peek data size -//--------------------------------------------------------------------- -int ikcp_peeksize(const ikcpcb *kcp) -{ - struct IQUEUEHEAD *p; - IKCPSEG *seg; - int length = 0; - - assert(kcp); - - if (iqueue_is_empty(&kcp->rcv_queue)) return -1; - - seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); - if (seg->frg == 0) return seg->len; - - if (kcp->nrcv_que < seg->frg + 1) return -1; - - for (p = kcp->rcv_queue.next; p != &kcp->rcv_queue; p = p->next) { - seg = iqueue_entry(p, IKCPSEG, node); - length += seg->len; - if (seg->frg == 0) break; - } - - return length; -} - - -//--------------------------------------------------------------------- -// user/upper level send, returns below zero for error -//--------------------------------------------------------------------- -int ikcp_send(ikcpcb *kcp, const char *buffer, int len) -{ - IKCPSEG *seg; - int count, i; - int sent = 0; - - assert(kcp->mss > 0); - if (len < 0) return -1; - - // append to previous segment in streaming mode (if possible) - if (kcp->stream != 0) { - if (!iqueue_is_empty(&kcp->snd_queue)) { - IKCPSEG *old = iqueue_entry(kcp->snd_queue.prev, IKCPSEG, node); - if (old->len < kcp->mss) { - int capacity = kcp->mss - old->len; - int extend = (len < capacity)? len : capacity; - seg = ikcp_segment_new(kcp, old->len + extend); - assert(seg); - if (seg == NULL) { - return -2; - } - iqueue_add_tail(&seg->node, &kcp->snd_queue); - memcpy(seg->data, old->data, old->len); - if (buffer) { - memcpy(seg->data + old->len, buffer, extend); - buffer += extend; - } - seg->len = old->len + extend; - seg->frg = 0; - len -= extend; - iqueue_del_init(&old->node); - ikcp_segment_delete(kcp, old); - sent = extend; - } - } - if (len <= 0) { - return sent; - } - } - - if (len <= (int)kcp->mss) count = 1; - else count = (len + kcp->mss - 1) / kcp->mss; - - if (count >= (int)IKCP_WND_RCV) { - if (kcp->stream != 0 && sent > 0) - return sent; - return -2; - } - - if (count == 0) count = 1; - - // fragment - for (i = 0; i < count; i++) { - int size = len > (int)kcp->mss ? (int)kcp->mss : len; - seg = ikcp_segment_new(kcp, size); - assert(seg); - if (seg == NULL) { - return -2; - } - if (buffer && len > 0) { - memcpy(seg->data, buffer, size); - } - seg->len = size; - seg->frg = (kcp->stream == 0)? (count - i - 1) : 0; - iqueue_init(&seg->node); - iqueue_add_tail(&seg->node, &kcp->snd_queue); - kcp->nsnd_que++; - if (buffer) { - buffer += size; - } - len -= size; - sent += size; - } - - return sent; -} - - -//--------------------------------------------------------------------- -// parse ack -//--------------------------------------------------------------------- -static void ikcp_update_ack(ikcpcb *kcp, IINT32 rtt) -{ - IINT32 rto = 0; - if (kcp->rx_srtt == 0) { - kcp->rx_srtt = rtt; - kcp->rx_rttval = rtt / 2; - } else { - long delta = rtt - kcp->rx_srtt; - if (delta < 0) delta = -delta; - kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4; - kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8; - if (kcp->rx_srtt < 1) kcp->rx_srtt = 1; - } - rto = kcp->rx_srtt + _imax_(kcp->interval, 4 * kcp->rx_rttval); - kcp->rx_rto = _ibound_(kcp->rx_minrto, rto, IKCP_RTO_MAX); -} - -static void ikcp_shrink_buf(ikcpcb *kcp) -{ - struct IQUEUEHEAD *p = kcp->snd_buf.next; - if (p != &kcp->snd_buf) { - IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); - kcp->snd_una = seg->sn; - } else { - kcp->snd_una = kcp->snd_nxt; - } -} - -static void ikcp_parse_ack(ikcpcb *kcp, IUINT32 sn) -{ - struct IQUEUEHEAD *p, *next; - - if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) - return; - - for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { - IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); - next = p->next; - if (sn == seg->sn) { - iqueue_del(p); - ikcp_segment_delete(kcp, seg); - kcp->nsnd_buf--; - break; - } - if (_itimediff(sn, seg->sn) < 0) { - break; - } - } -} - -static void ikcp_parse_una(ikcpcb *kcp, IUINT32 una) -{ - struct IQUEUEHEAD *p, *next; - for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { - IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); - next = p->next; - if (_itimediff(una, seg->sn) > 0) { - iqueue_del(p); - ikcp_segment_delete(kcp, seg); - kcp->nsnd_buf--; - } else { - break; - } - } -} - -static void ikcp_parse_fastack(ikcpcb *kcp, IUINT32 sn, IUINT32 ts) -{ - struct IQUEUEHEAD *p, *next; - - if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) - return; - - for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { - IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); - next = p->next; - if (_itimediff(sn, seg->sn) < 0) { - break; - } - else if (sn != seg->sn) { - #ifndef IKCP_FASTACK_CONSERVE - seg->fastack++; - #else - if (_itimediff(ts, seg->ts) >= 0) - seg->fastack++; - #endif - } - } -} - - -//--------------------------------------------------------------------- -// ack append -//--------------------------------------------------------------------- -static void ikcp_ack_push(ikcpcb *kcp, IUINT32 sn, IUINT32 ts) -{ - IUINT32 newsize = kcp->ackcount + 1; - IUINT32 *ptr; - - if (newsize > kcp->ackblock) { - IUINT32 *acklist; - IUINT32 newblock; - - for (newblock = 8; newblock < newsize; newblock <<= 1); - acklist = (IUINT32*)ikcp_malloc(newblock * sizeof(IUINT32) * 2); - - if (acklist == NULL) { - assert(acklist != NULL); - abort(); - } - - if (kcp->acklist != NULL) { - IUINT32 x; - for (x = 0; x < kcp->ackcount; x++) { - acklist[x * 2 + 0] = kcp->acklist[x * 2 + 0]; - acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1]; - } - ikcp_free(kcp->acklist); - } - - kcp->acklist = acklist; - kcp->ackblock = newblock; - } - - ptr = &kcp->acklist[kcp->ackcount * 2]; - ptr[0] = sn; - ptr[1] = ts; - kcp->ackcount++; -} - -static void ikcp_ack_get(const ikcpcb *kcp, int p, IUINT32 *sn, IUINT32 *ts) -{ - if (sn) sn[0] = kcp->acklist[p * 2 + 0]; - if (ts) ts[0] = kcp->acklist[p * 2 + 1]; -} - - -//--------------------------------------------------------------------- -// parse data -//--------------------------------------------------------------------- -void ikcp_parse_data(ikcpcb *kcp, IKCPSEG *newseg) -{ - struct IQUEUEHEAD *p, *prev; - IUINT32 sn = newseg->sn; - int repeat = 0; - - if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) >= 0 || - _itimediff(sn, kcp->rcv_nxt) < 0) { - ikcp_segment_delete(kcp, newseg); - return; - } - - for (p = kcp->rcv_buf.prev; p != &kcp->rcv_buf; p = prev) { - IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); - prev = p->prev; - if (seg->sn == sn) { - repeat = 1; - break; - } - if (_itimediff(sn, seg->sn) > 0) { - break; - } - } - - if (repeat == 0) { - iqueue_init(&newseg->node); - iqueue_add(&newseg->node, p); - kcp->nrcv_buf++; - } else { - ikcp_segment_delete(kcp, newseg); - } - -#if 0 - ikcp_qprint("rcvbuf", &kcp->rcv_buf); - printf("rcv_nxt=%lu\n", kcp->rcv_nxt); -#endif - - // move available data from rcv_buf -> rcv_queue - while (! iqueue_is_empty(&kcp->rcv_buf)) { - IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); - if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { - iqueue_del(&seg->node); - kcp->nrcv_buf--; - iqueue_add_tail(&seg->node, &kcp->rcv_queue); - kcp->nrcv_que++; - kcp->rcv_nxt++; - } else { - break; - } - } - -#if 0 - ikcp_qprint("queue", &kcp->rcv_queue); - printf("rcv_nxt=%lu\n", kcp->rcv_nxt); -#endif - -#if 1 -// printf("snd(buf=%d, queue=%d)\n", kcp->nsnd_buf, kcp->nsnd_que); -// printf("rcv(buf=%d, queue=%d)\n", kcp->nrcv_buf, kcp->nrcv_que); -#endif -} - - -//--------------------------------------------------------------------- -// input data -//--------------------------------------------------------------------- -int ikcp_input(ikcpcb *kcp, const char *data, long size) -{ - IUINT32 prev_una = kcp->snd_una; - IUINT32 maxack = 0, latest_ts = 0; - int flag = 0; - - if (ikcp_canlog(kcp, IKCP_LOG_INPUT)) { - ikcp_log(kcp, IKCP_LOG_INPUT, "[RI] %d bytes", (int)size); - } - - if (data == NULL || (int)size < (int)IKCP_OVERHEAD) return -1; - - while (1) { - IUINT32 ts, sn, len, una, conv; - IUINT16 wnd; - IUINT8 cmd, frg; - IKCPSEG *seg; - - if (size < (int)IKCP_OVERHEAD) break; - - data = ikcp_decode32u(data, &conv); - if (conv != kcp->conv) return -1; - - data = ikcp_decode8u(data, &cmd); - data = ikcp_decode8u(data, &frg); - data = ikcp_decode16u(data, &wnd); - data = ikcp_decode32u(data, &ts); - data = ikcp_decode32u(data, &sn); - data = ikcp_decode32u(data, &una); - data = ikcp_decode32u(data, &len); - - size -= IKCP_OVERHEAD; - - if ((long)size < (long)len || (int)len < 0) return -2; - - if (cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK && - cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS) - return -3; - - kcp->rmt_wnd = wnd; - ikcp_parse_una(kcp, una); - ikcp_shrink_buf(kcp); - - if (cmd == IKCP_CMD_ACK) { - if (_itimediff(kcp->current, ts) >= 0) { - ikcp_update_ack(kcp, _itimediff(kcp->current, ts)); - } - ikcp_parse_ack(kcp, sn); - ikcp_shrink_buf(kcp); - if (flag == 0) { - flag = 1; - maxack = sn; - latest_ts = ts; - } else { - if (_itimediff(sn, maxack) > 0) { - #ifndef IKCP_FASTACK_CONSERVE - maxack = sn; - latest_ts = ts; - #else - if (_itimediff(ts, latest_ts) > 0) { - maxack = sn; - latest_ts = ts; - } - #endif - } - } - if (ikcp_canlog(kcp, IKCP_LOG_IN_ACK)) { - ikcp_log(kcp, IKCP_LOG_IN_ACK, - "input ack: sn=%lu rtt=%ld rto=%ld", (unsigned long)sn, - (long)_itimediff(kcp->current, ts), - (long)kcp->rx_rto); - } - } - else if (cmd == IKCP_CMD_PUSH) { - if (ikcp_canlog(kcp, IKCP_LOG_IN_DATA)) { - ikcp_log(kcp, IKCP_LOG_IN_DATA, - "input psh: sn=%lu ts=%lu", (unsigned long)sn, (unsigned long)ts); - } - if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) < 0) { - ikcp_ack_push(kcp, sn, ts); - if (_itimediff(sn, kcp->rcv_nxt) >= 0) { - seg = ikcp_segment_new(kcp, len); - seg->conv = conv; - seg->cmd = cmd; - seg->frg = frg; - seg->wnd = wnd; - seg->ts = ts; - seg->sn = sn; - seg->una = una; - seg->len = len; - - if (len > 0) { - memcpy(seg->data, data, len); - } - - ikcp_parse_data(kcp, seg); - } - } - } - else if (cmd == IKCP_CMD_WASK) { - // ready to send back IKCP_CMD_WINS in ikcp_flush - // tell remote my window size - kcp->probe |= IKCP_ASK_TELL; - if (ikcp_canlog(kcp, IKCP_LOG_IN_PROBE)) { - ikcp_log(kcp, IKCP_LOG_IN_PROBE, "input probe"); - } - } - else if (cmd == IKCP_CMD_WINS) { - // do nothing - if (ikcp_canlog(kcp, IKCP_LOG_IN_WINS)) { - ikcp_log(kcp, IKCP_LOG_IN_WINS, - "input wins: %lu", (unsigned long)(wnd)); - } - } - else { - return -3; - } - - data += len; - size -= len; - } - - if (flag != 0) { - ikcp_parse_fastack(kcp, maxack, latest_ts); - } - - if (_itimediff(kcp->snd_una, prev_una) > 0) { - if (kcp->cwnd < kcp->rmt_wnd) { - IUINT32 mss = kcp->mss; - if (kcp->cwnd < kcp->ssthresh) { - kcp->cwnd++; - kcp->incr += mss; - } else { - if (kcp->incr < mss) kcp->incr = mss; - kcp->incr += (mss * mss) / kcp->incr + (mss / 16); - if ((kcp->cwnd + 1) * mss <= kcp->incr) { - #if 1 - kcp->cwnd = (kcp->incr + mss - 1) / ((mss > 0)? mss : 1); - #else - kcp->cwnd++; - #endif - } - } - if (kcp->cwnd > kcp->rmt_wnd) { - kcp->cwnd = kcp->rmt_wnd; - kcp->incr = kcp->rmt_wnd * mss; - } - } - } - - return 0; -} - - -//--------------------------------------------------------------------- -// ikcp_encode_seg -//--------------------------------------------------------------------- -static char *ikcp_encode_seg(char *ptr, const IKCPSEG *seg) -{ - ptr = ikcp_encode32u(ptr, seg->conv); - ptr = ikcp_encode8u(ptr, (IUINT8)seg->cmd); - ptr = ikcp_encode8u(ptr, (IUINT8)seg->frg); - ptr = ikcp_encode16u(ptr, (IUINT16)seg->wnd); - ptr = ikcp_encode32u(ptr, seg->ts); - ptr = ikcp_encode32u(ptr, seg->sn); - ptr = ikcp_encode32u(ptr, seg->una); - ptr = ikcp_encode32u(ptr, seg->len); - return ptr; -} - -static int ikcp_wnd_unused(const ikcpcb *kcp) -{ - if (kcp->nrcv_que < kcp->rcv_wnd) { - return kcp->rcv_wnd - kcp->nrcv_que; - } - return 0; -} - - -//--------------------------------------------------------------------- -// ikcp_flush -//--------------------------------------------------------------------- -void ikcp_flush(ikcpcb *kcp) -{ - IUINT32 current = kcp->current; - char *buffer = kcp->buffer; - char *ptr = buffer; - int count, size, i; - IUINT32 resent, cwnd; - IUINT32 rtomin; - struct IQUEUEHEAD *p; - int change = 0; - int lost = 0; - IKCPSEG seg; - - // 'ikcp_update' haven't been called. - if (kcp->updated == 0) return; - - seg.conv = kcp->conv; - seg.cmd = IKCP_CMD_ACK; - seg.frg = 0; - seg.wnd = ikcp_wnd_unused(kcp); - seg.una = kcp->rcv_nxt; - seg.len = 0; - seg.sn = 0; - seg.ts = 0; - - // flush acknowledges - count = kcp->ackcount; - for (i = 0; i < count; i++) { - size = (int)(ptr - buffer); - if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { - ikcp_output(kcp, buffer, size); - ptr = buffer; - } - ikcp_ack_get(kcp, i, &seg.sn, &seg.ts); - ptr = ikcp_encode_seg(ptr, &seg); - } - - kcp->ackcount = 0; - - // probe window size (if remote window size equals zero) - if (kcp->rmt_wnd == 0) { - if (kcp->probe_wait == 0) { - kcp->probe_wait = IKCP_PROBE_INIT; - kcp->ts_probe = kcp->current + kcp->probe_wait; - } - else { - if (_itimediff(kcp->current, kcp->ts_probe) >= 0) { - if (kcp->probe_wait < IKCP_PROBE_INIT) - kcp->probe_wait = IKCP_PROBE_INIT; - kcp->probe_wait += kcp->probe_wait / 2; - if (kcp->probe_wait > IKCP_PROBE_LIMIT) - kcp->probe_wait = IKCP_PROBE_LIMIT; - kcp->ts_probe = kcp->current + kcp->probe_wait; - kcp->probe |= IKCP_ASK_SEND; - } - } - } else { - kcp->ts_probe = 0; - kcp->probe_wait = 0; - } - - // flush window probing commands - if (kcp->probe & IKCP_ASK_SEND) { - seg.cmd = IKCP_CMD_WASK; - size = (int)(ptr - buffer); - if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { - ikcp_output(kcp, buffer, size); - ptr = buffer; - } - ptr = ikcp_encode_seg(ptr, &seg); - } - - // flush window probing commands - if (kcp->probe & IKCP_ASK_TELL) { - seg.cmd = IKCP_CMD_WINS; - size = (int)(ptr - buffer); - if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { - ikcp_output(kcp, buffer, size); - ptr = buffer; - } - ptr = ikcp_encode_seg(ptr, &seg); - } - - kcp->probe = 0; - - // calculate window size - cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd); - if (kcp->nocwnd == 0) cwnd = _imin_(kcp->cwnd, cwnd); - - // move data from snd_queue to snd_buf - while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) { - IKCPSEG *newseg; - if (iqueue_is_empty(&kcp->snd_queue)) break; - - newseg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); - - iqueue_del(&newseg->node); - iqueue_add_tail(&newseg->node, &kcp->snd_buf); - kcp->nsnd_que--; - kcp->nsnd_buf++; - - newseg->conv = kcp->conv; - newseg->cmd = IKCP_CMD_PUSH; - newseg->wnd = seg.wnd; - newseg->ts = current; - newseg->sn = kcp->snd_nxt++; - newseg->una = kcp->rcv_nxt; - newseg->resendts = current; - newseg->rto = kcp->rx_rto; - newseg->fastack = 0; - newseg->xmit = 0; - } - - // calculate resent - resent = (kcp->fastresend > 0)? (IUINT32)kcp->fastresend : 0xffffffff; - rtomin = (kcp->nodelay == 0)? (kcp->rx_rto >> 3) : 0; - - // flush data segments - for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { - IKCPSEG *segment = iqueue_entry(p, IKCPSEG, node); - int needsend = 0; - if (segment->xmit == 0) { - needsend = 1; - segment->xmit++; - segment->rto = kcp->rx_rto; - segment->resendts = current + segment->rto + rtomin; - } - else if (_itimediff(current, segment->resendts) >= 0) { - needsend = 1; - segment->xmit++; - kcp->xmit++; - if (kcp->nodelay == 0) { - segment->rto += _imax_(segment->rto, (IUINT32)kcp->rx_rto); - } else { - IINT32 step = (kcp->nodelay < 2)? - ((IINT32)(segment->rto)) : kcp->rx_rto; - segment->rto += step / 2; - } - segment->resendts = current + segment->rto; - lost = 1; - } - else if (segment->fastack >= resent) { - if ((int)segment->xmit <= kcp->fastlimit || - kcp->fastlimit <= 0) { - needsend = 1; - segment->xmit++; - segment->fastack = 0; - segment->resendts = current + segment->rto; - change++; - } - } - - if (needsend) { - int need; - segment->ts = current; - segment->wnd = seg.wnd; - segment->una = kcp->rcv_nxt; - - size = (int)(ptr - buffer); - need = IKCP_OVERHEAD + segment->len; - - if (size + need > (int)kcp->mtu) { - ikcp_output(kcp, buffer, size); - ptr = buffer; - } - - ptr = ikcp_encode_seg(ptr, segment); - - if (segment->len > 0) { - memcpy(ptr, segment->data, segment->len); - ptr += segment->len; - } - - if (segment->xmit >= kcp->dead_link) { - kcp->state = (IUINT32)-1; - } - } - } - - // flash remain segments - size = (int)(ptr - buffer); - if (size > 0) { - ikcp_output(kcp, buffer, size); - } - - // update ssthresh - if (change) { - IUINT32 inflight = kcp->snd_nxt - kcp->snd_una; - kcp->ssthresh = inflight / 2; - if (kcp->ssthresh < IKCP_THRESH_MIN) - kcp->ssthresh = IKCP_THRESH_MIN; - kcp->cwnd = kcp->ssthresh + resent; - kcp->incr = kcp->cwnd * kcp->mss; - } - - if (lost) { - kcp->ssthresh = cwnd / 2; - if (kcp->ssthresh < IKCP_THRESH_MIN) - kcp->ssthresh = IKCP_THRESH_MIN; - kcp->cwnd = 1; - kcp->incr = kcp->mss; - } - - if (kcp->cwnd < 1) { - kcp->cwnd = 1; - kcp->incr = kcp->mss; - } -} - - -//--------------------------------------------------------------------- -// update state (call it repeatedly, every 10ms-100ms), or you can ask -// ikcp_check when to call it again (without ikcp_input/_send calling). -// 'current' - current timestamp in millisec. -//--------------------------------------------------------------------- -void ikcp_update(ikcpcb *kcp, IUINT32 current) -{ - IINT32 slap; - - kcp->current = current; - - if (kcp->updated == 0) { - kcp->updated = 1; - kcp->ts_flush = kcp->current; - } - - slap = _itimediff(kcp->current, kcp->ts_flush); - - if (slap >= 10000 || slap < -10000) { - kcp->ts_flush = kcp->current; - slap = 0; - } - - if (slap >= 0) { - kcp->ts_flush += kcp->interval; - if (_itimediff(kcp->current, kcp->ts_flush) >= 0) { - kcp->ts_flush = kcp->current + kcp->interval; - } - ikcp_flush(kcp); - } -} - - -//--------------------------------------------------------------------- -// Determine when should you invoke ikcp_update: -// returns when you should invoke ikcp_update in millisec, if there -// is no ikcp_input/_send calling. you can call ikcp_update in that -// time, instead of call update repeatly. -// Important to reduce unnacessary ikcp_update invoking. use it to -// schedule ikcp_update (eg. implementing an epoll-like mechanism, -// or optimize ikcp_update when handling massive kcp connections) -//--------------------------------------------------------------------- -IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current) -{ - IUINT32 ts_flush = kcp->ts_flush; - IINT32 tm_flush = 0x7fffffff; - IINT32 tm_packet = 0x7fffffff; - IUINT32 minimal = 0; - struct IQUEUEHEAD *p; - - if (kcp->updated == 0) { - return current; - } - - if (_itimediff(current, ts_flush) >= 10000 || - _itimediff(current, ts_flush) < -10000) { - ts_flush = current; - } - - if (_itimediff(current, ts_flush) >= 0) { - return current; - } - - tm_flush = _itimediff(ts_flush, current); - - for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { - const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); - IINT32 diff = _itimediff(seg->resendts, current); - if (diff <= 0) { - return current; - } - if (diff < tm_packet) tm_packet = diff; - } - - minimal = (IUINT32)(tm_packet < tm_flush ? tm_packet : tm_flush); - if (minimal >= kcp->interval) minimal = kcp->interval; - - return current + minimal; -} - - - -int ikcp_setmtu(ikcpcb *kcp, int mtu) -{ - char *buffer; - if (mtu < 50 || mtu < (int)IKCP_OVERHEAD) - return -1; - buffer = (char*)ikcp_malloc((mtu + IKCP_OVERHEAD) * 3); - if (buffer == NULL) - return -2; - kcp->mtu = mtu; - kcp->mss = kcp->mtu - IKCP_OVERHEAD; - ikcp_free(kcp->buffer); - kcp->buffer = buffer; - return 0; -} - -int ikcp_interval(ikcpcb *kcp, int interval) -{ - if (interval > 5000) interval = 5000; - else if (interval < 10) interval = 10; - kcp->interval = interval; - return 0; -} - -int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc) -{ - if (nodelay >= 0) { - kcp->nodelay = nodelay; - if (nodelay) { - kcp->rx_minrto = IKCP_RTO_NDL; - } - else { - kcp->rx_minrto = IKCP_RTO_MIN; - } - } - if (interval >= 0) { - if (interval > 5000) interval = 5000; - else if (interval < 10) interval = 10; - kcp->interval = interval; - } - if (resend >= 0) { - kcp->fastresend = resend; - } - if (nc >= 0) { - kcp->nocwnd = nc; - } - return 0; -} - - -int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd) -{ - if (kcp) { - if (sndwnd > 0) { - kcp->snd_wnd = sndwnd; - } - if (rcvwnd > 0) { // must >= max fragment size - kcp->rcv_wnd = _imax_(rcvwnd, IKCP_WND_RCV); - } - } - return 0; -} - -int ikcp_waitsnd(const ikcpcb *kcp) -{ - return kcp->nsnd_buf + kcp->nsnd_que; -} - - -// read conv -IUINT32 ikcp_getconv(const void *ptr) -{ - IUINT32 conv; - ikcp_decode32u((const char*)ptr, &conv); - return conv; -} - - +//===================================================================== +// +// KCP - A Better ARQ Protocol Implementation +// skywind3000 (at) gmail.com, 2010-2011 +// +// Features: +// + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. +// + Maximum RTT reduce three times vs tcp. +// + Lightweight, distributed as a single source file. +// +//===================================================================== +#include "ikcp.h" + +#include +#include +#include +#include +#include + + + +//===================================================================== +// KCP BASIC +//===================================================================== +const IUINT32 IKCP_RTO_NDL = 30; // no delay min rto +const IUINT32 IKCP_RTO_MIN = 100; // normal min rto +const IUINT32 IKCP_RTO_DEF = 200; +const IUINT32 IKCP_RTO_MAX = 60000; +const IUINT32 IKCP_CMD_PUSH = 81; // cmd: push data +const IUINT32 IKCP_CMD_ACK = 82; // cmd: ack +const IUINT32 IKCP_CMD_WASK = 83; // cmd: window probe (ask) +const IUINT32 IKCP_CMD_WINS = 84; // cmd: window size (tell) +const IUINT32 IKCP_ASK_SEND = 1; // need to send IKCP_CMD_WASK +const IUINT32 IKCP_ASK_TELL = 2; // need to send IKCP_CMD_WINS +const IUINT32 IKCP_WND_SND = 32; +const IUINT32 IKCP_WND_RCV = 128; // must >= max fragment size +const IUINT32 IKCP_MTU_DEF = 1400; +const IUINT32 IKCP_ACK_FAST = 3; +const IUINT32 IKCP_INTERVAL = 100; +const IUINT32 IKCP_OVERHEAD = 24; +const IUINT32 IKCP_DEADLINK = 20; +const IUINT32 IKCP_THRESH_INIT = 2; +const IUINT32 IKCP_THRESH_MIN = 2; +const IUINT32 IKCP_PROBE_INIT = 7000; // 7 secs to probe window size +const IUINT32 IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window +const IUINT32 IKCP_FASTACK_LIMIT = 5; // max times to trigger fastack + + +//--------------------------------------------------------------------- +// encode / decode +//--------------------------------------------------------------------- + +/* encode 8 bits unsigned int */ +static inline char *ikcp_encode8u(char *p, unsigned char c) +{ + *(unsigned char*)p++ = c; + return p; +} + +/* decode 8 bits unsigned int */ +static inline const char *ikcp_decode8u(const char *p, unsigned char *c) +{ + *c = *(unsigned char*)p++; + return p; +} + +/* encode 16 bits unsigned int (lsb) */ +static inline char *ikcp_encode16u(char *p, unsigned short w) +{ +#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN + *(unsigned char*)(p + 0) = (w & 255); + *(unsigned char*)(p + 1) = (w >> 8); +#else + memcpy(p, &w, 2); +#endif + p += 2; + return p; +} + +/* decode 16 bits unsigned int (lsb) */ +static inline const char *ikcp_decode16u(const char *p, unsigned short *w) +{ +#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN + *w = *(const unsigned char*)(p + 1); + *w = *(const unsigned char*)(p + 0) + (*w << 8); +#else + memcpy(w, p, 2); +#endif + p += 2; + return p; +} + +/* encode 32 bits unsigned int (lsb) */ +static inline char *ikcp_encode32u(char *p, IUINT32 l) +{ +#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN + *(unsigned char*)(p + 0) = (unsigned char)((l >> 0) & 0xff); + *(unsigned char*)(p + 1) = (unsigned char)((l >> 8) & 0xff); + *(unsigned char*)(p + 2) = (unsigned char)((l >> 16) & 0xff); + *(unsigned char*)(p + 3) = (unsigned char)((l >> 24) & 0xff); +#else + memcpy(p, &l, 4); +#endif + p += 4; + return p; +} + +/* decode 32 bits unsigned int (lsb) */ +static inline const char *ikcp_decode32u(const char *p, IUINT32 *l) +{ +#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN + *l = *(const unsigned char*)(p + 3); + *l = *(const unsigned char*)(p + 2) + (*l << 8); + *l = *(const unsigned char*)(p + 1) + (*l << 8); + *l = *(const unsigned char*)(p + 0) + (*l << 8); +#else + memcpy(l, p, 4); +#endif + p += 4; + return p; +} + +static inline IUINT32 _imin_(IUINT32 a, IUINT32 b) { + return a <= b ? a : b; +} + +static inline IUINT32 _imax_(IUINT32 a, IUINT32 b) { + return a >= b ? a : b; +} + +static inline IUINT32 _ibound_(IUINT32 lower, IUINT32 middle, IUINT32 upper) +{ + return _imin_(_imax_(lower, middle), upper); +} + +static inline long _itimediff(IUINT32 later, IUINT32 earlier) +{ + return ((IINT32)(later - earlier)); +} + +//--------------------------------------------------------------------- +// manage segment +//--------------------------------------------------------------------- +typedef struct IKCPSEG IKCPSEG; + +static void* (*ikcp_malloc_hook)(size_t) = NULL; +static void (*ikcp_free_hook)(void *) = NULL; + +// internal malloc +static void* ikcp_malloc(size_t size) { + if (ikcp_malloc_hook) + return ikcp_malloc_hook(size); + return malloc(size); +} + +// internal free +static void ikcp_free(void *ptr) { + if (ikcp_free_hook) { + ikcp_free_hook(ptr); + } else { + free(ptr); + } +} + +// redefine allocator +void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)) +{ + ikcp_malloc_hook = new_malloc; + ikcp_free_hook = new_free; +} + +// allocate a new kcp segment +static IKCPSEG* ikcp_segment_new(ikcpcb *kcp, int size) +{ + return (IKCPSEG*)ikcp_malloc(sizeof(IKCPSEG) + size); +} + +// delete a segment +static void ikcp_segment_delete(ikcpcb *kcp, IKCPSEG *seg) +{ + ikcp_free(seg); +} + +// write log +void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...) +{ + char buffer[1024]; + va_list argptr; + if ((mask & kcp->logmask) == 0 || kcp->writelog == 0) return; + va_start(argptr, fmt); + vsprintf(buffer, fmt, argptr); + va_end(argptr); + kcp->writelog(buffer, kcp, kcp->user); +} + +// check log mask +static int ikcp_canlog(const ikcpcb *kcp, int mask) +{ + if ((mask & kcp->logmask) == 0 || kcp->writelog == NULL) return 0; + return 1; +} + +// output segment +static int ikcp_output(ikcpcb *kcp, const void *data, int size) +{ + assert(kcp); + assert(kcp->output); + if (ikcp_canlog(kcp, IKCP_LOG_OUTPUT)) { + ikcp_log(kcp, IKCP_LOG_OUTPUT, "[RO] %ld bytes", (long)size); + } + if (size == 0) return 0; + return kcp->output((const char*)data, size, kcp, kcp->user); +} + +// output queue +void ikcp_qprint(const char *name, const struct IQUEUEHEAD *head) +{ +#if 0 + const struct IQUEUEHEAD *p; + printf("<%s>: [", name); + for (p = head->next; p != head; p = p->next) { + const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); + printf("(%lu %d)", (unsigned long)seg->sn, (int)(seg->ts % 10000)); + if (p->next != head) printf(","); + } + printf("]\n"); +#endif +} + + +//--------------------------------------------------------------------- +// create a new kcpcb +//--------------------------------------------------------------------- +ikcpcb* ikcp_create(IUINT32 conv, void *user) +{ + ikcpcb *kcp = (ikcpcb*)ikcp_malloc(sizeof(struct IKCPCB)); + if (kcp == NULL) return NULL; + kcp->conv = conv; + kcp->user = user; + kcp->snd_una = 0; + kcp->snd_nxt = 0; + kcp->rcv_nxt = 0; + kcp->ts_recent = 0; + kcp->ts_lastack = 0; + kcp->ts_probe = 0; + kcp->probe_wait = 0; + kcp->snd_wnd = IKCP_WND_SND; + kcp->rcv_wnd = IKCP_WND_RCV; + kcp->rmt_wnd = IKCP_WND_RCV; + kcp->cwnd = 0; + kcp->incr = 0; + kcp->probe = 0; + kcp->mtu = IKCP_MTU_DEF; + kcp->mss = kcp->mtu - IKCP_OVERHEAD; + kcp->stream = 0; + + kcp->buffer = (char*)ikcp_malloc((kcp->mtu + IKCP_OVERHEAD) * 3); + if (kcp->buffer == NULL) { + ikcp_free(kcp); + return NULL; + } + + iqueue_init(&kcp->snd_queue); + iqueue_init(&kcp->rcv_queue); + iqueue_init(&kcp->snd_buf); + iqueue_init(&kcp->rcv_buf); + kcp->nrcv_buf = 0; + kcp->nsnd_buf = 0; + kcp->nrcv_que = 0; + kcp->nsnd_que = 0; + kcp->state = 0; + kcp->acklist = NULL; + kcp->ackblock = 0; + kcp->ackcount = 0; + kcp->rx_srtt = 0; + kcp->rx_rttval = 0; + kcp->rx_rto = IKCP_RTO_DEF; + kcp->rx_minrto = IKCP_RTO_MIN; + kcp->current = 0; + kcp->interval = IKCP_INTERVAL; + kcp->ts_flush = IKCP_INTERVAL; + kcp->nodelay = 0; + kcp->updated = 0; + kcp->logmask = 0; + kcp->ssthresh = IKCP_THRESH_INIT; + kcp->fastresend = 0; + kcp->fastlimit = IKCP_FASTACK_LIMIT; + kcp->nocwnd = 0; + kcp->xmit = 0; + kcp->dead_link = IKCP_DEADLINK; + kcp->output = NULL; + kcp->writelog = NULL; + + return kcp; +} + + +//--------------------------------------------------------------------- +// release a new kcpcb +//--------------------------------------------------------------------- +void ikcp_release(ikcpcb *kcp) +{ + assert(kcp); + if (kcp) { + IKCPSEG *seg; + while (!iqueue_is_empty(&kcp->snd_buf)) { + seg = iqueue_entry(kcp->snd_buf.next, IKCPSEG, node); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + while (!iqueue_is_empty(&kcp->rcv_buf)) { + seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + while (!iqueue_is_empty(&kcp->snd_queue)) { + seg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + while (!iqueue_is_empty(&kcp->rcv_queue)) { + seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + if (kcp->buffer) { + ikcp_free(kcp->buffer); + } + if (kcp->acklist) { + ikcp_free(kcp->acklist); + } + + kcp->nrcv_buf = 0; + kcp->nsnd_buf = 0; + kcp->nrcv_que = 0; + kcp->nsnd_que = 0; + kcp->ackcount = 0; + kcp->buffer = NULL; + kcp->acklist = NULL; + ikcp_free(kcp); + } +} + + +//--------------------------------------------------------------------- +// set output callback, which will be invoked by kcp +//--------------------------------------------------------------------- +void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, + ikcpcb *kcp, void *user)) +{ + kcp->output = output; +} + + +//--------------------------------------------------------------------- +// user/upper level recv: returns size, returns below zero for EAGAIN +//--------------------------------------------------------------------- +int ikcp_recv(ikcpcb *kcp, char *buffer, int len) +{ + struct IQUEUEHEAD *p; + int ispeek = (len < 0)? 1 : 0; + int peeksize; + int recover = 0; + IKCPSEG *seg; + assert(kcp); + + if (iqueue_is_empty(&kcp->rcv_queue)) + return -1; + + if (len < 0) len = -len; + + peeksize = ikcp_peeksize(kcp); + + if (peeksize < 0) + return -2; + + if (peeksize > len) + return -3; + + if (kcp->nrcv_que >= kcp->rcv_wnd) + recover = 1; + + // merge fragment + for (len = 0, p = kcp->rcv_queue.next; p != &kcp->rcv_queue; ) { + int fragment; + seg = iqueue_entry(p, IKCPSEG, node); + p = p->next; + + if (buffer) { + memcpy(buffer, seg->data, seg->len); + buffer += seg->len; + } + + len += seg->len; + fragment = seg->frg; + + if (ikcp_canlog(kcp, IKCP_LOG_RECV)) { + ikcp_log(kcp, IKCP_LOG_RECV, "recv sn=%lu", (unsigned long)seg->sn); + } + + if (ispeek == 0) { + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + kcp->nrcv_que--; + } + + if (fragment == 0) + break; + } + + assert(len == peeksize); + + // move available data from rcv_buf -> rcv_queue + while (! iqueue_is_empty(&kcp->rcv_buf)) { + seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); + if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { + iqueue_del(&seg->node); + kcp->nrcv_buf--; + iqueue_add_tail(&seg->node, &kcp->rcv_queue); + kcp->nrcv_que++; + kcp->rcv_nxt++; + } else { + break; + } + } + + // fast recover + if (kcp->nrcv_que < kcp->rcv_wnd && recover) { + // ready to send back IKCP_CMD_WINS in ikcp_flush + // tell remote my window size + kcp->probe |= IKCP_ASK_TELL; + } + + return len; +} + + +//--------------------------------------------------------------------- +// peek data size +//--------------------------------------------------------------------- +int ikcp_peeksize(const ikcpcb *kcp) +{ + struct IQUEUEHEAD *p; + IKCPSEG *seg; + int length = 0; + + assert(kcp); + + if (iqueue_is_empty(&kcp->rcv_queue)) return -1; + + seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); + if (seg->frg == 0) return seg->len; + + if (kcp->nrcv_que < seg->frg + 1) return -1; + + for (p = kcp->rcv_queue.next; p != &kcp->rcv_queue; p = p->next) { + seg = iqueue_entry(p, IKCPSEG, node); + length += seg->len; + if (seg->frg == 0) break; + } + + return length; +} + + +//--------------------------------------------------------------------- +// user/upper level send, returns below zero for error +//--------------------------------------------------------------------- +int ikcp_send(ikcpcb *kcp, const char *buffer, int len) +{ + IKCPSEG *seg; + int count, i; + int sent = 0; + + assert(kcp->mss > 0); + if (len < 0) return -1; + + // append to previous segment in streaming mode (if possible) + if (kcp->stream != 0) { + if (!iqueue_is_empty(&kcp->snd_queue)) { + IKCPSEG *old = iqueue_entry(kcp->snd_queue.prev, IKCPSEG, node); + if (old->len < kcp->mss) { + int capacity = kcp->mss - old->len; + int extend = (len < capacity)? len : capacity; + seg = ikcp_segment_new(kcp, old->len + extend); + assert(seg); + if (seg == NULL) { + return -2; + } + iqueue_add_tail(&seg->node, &kcp->snd_queue); + memcpy(seg->data, old->data, old->len); + if (buffer) { + memcpy(seg->data + old->len, buffer, extend); + buffer += extend; + } + seg->len = old->len + extend; + seg->frg = 0; + len -= extend; + iqueue_del_init(&old->node); + ikcp_segment_delete(kcp, old); + sent = extend; + } + } + if (len <= 0) { + return sent; + } + } + + if (len <= (int)kcp->mss) count = 1; + else count = (len + kcp->mss - 1) / kcp->mss; + + if (count >= (int)IKCP_WND_RCV) { + if (kcp->stream != 0 && sent > 0) + return sent; + return -2; + } + + if (count == 0) count = 1; + + // fragment + for (i = 0; i < count; i++) { + int size = len > (int)kcp->mss ? (int)kcp->mss : len; + seg = ikcp_segment_new(kcp, size); + assert(seg); + if (seg == NULL) { + return -2; + } + if (buffer && len > 0) { + memcpy(seg->data, buffer, size); + } + seg->len = size; + seg->frg = (kcp->stream == 0)? (count - i - 1) : 0; + iqueue_init(&seg->node); + iqueue_add_tail(&seg->node, &kcp->snd_queue); + kcp->nsnd_que++; + if (buffer) { + buffer += size; + } + len -= size; + sent += size; + } + + return sent; +} + + +//--------------------------------------------------------------------- +// parse ack +//--------------------------------------------------------------------- +static void ikcp_update_ack(ikcpcb *kcp, IINT32 rtt) +{ + IINT32 rto = 0; + if (kcp->rx_srtt == 0) { + kcp->rx_srtt = rtt; + kcp->rx_rttval = rtt / 2; + } else { + long delta = rtt - kcp->rx_srtt; + if (delta < 0) delta = -delta; + kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4; + kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8; + if (kcp->rx_srtt < 1) kcp->rx_srtt = 1; + } + rto = kcp->rx_srtt + _imax_(kcp->interval, 4 * kcp->rx_rttval); + kcp->rx_rto = _ibound_(kcp->rx_minrto, rto, IKCP_RTO_MAX); +} + +static void ikcp_shrink_buf(ikcpcb *kcp) +{ + struct IQUEUEHEAD *p = kcp->snd_buf.next; + if (p != &kcp->snd_buf) { + IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); + kcp->snd_una = seg->sn; + } else { + kcp->snd_una = kcp->snd_nxt; + } +} + +static void ikcp_parse_ack(ikcpcb *kcp, IUINT32 sn) +{ + struct IQUEUEHEAD *p, *next; + + if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) + return; + + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { + IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); + next = p->next; + if (sn == seg->sn) { + iqueue_del(p); + ikcp_segment_delete(kcp, seg); + kcp->nsnd_buf--; + break; + } + if (_itimediff(sn, seg->sn) < 0) { + break; + } + } +} + +static void ikcp_parse_una(ikcpcb *kcp, IUINT32 una) +{ + struct IQUEUEHEAD *p, *next; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { + IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); + next = p->next; + if (_itimediff(una, seg->sn) > 0) { + iqueue_del(p); + ikcp_segment_delete(kcp, seg); + kcp->nsnd_buf--; + } else { + break; + } + } +} + +static void ikcp_parse_fastack(ikcpcb *kcp, IUINT32 sn, IUINT32 ts) +{ + struct IQUEUEHEAD *p, *next; + + if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) + return; + + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { + IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); + next = p->next; + if (_itimediff(sn, seg->sn) < 0) { + break; + } + else if (sn != seg->sn) { + #ifndef IKCP_FASTACK_CONSERVE + seg->fastack++; + #else + if (_itimediff(ts, seg->ts) >= 0) + seg->fastack++; + #endif + } + } +} + + +//--------------------------------------------------------------------- +// ack append +//--------------------------------------------------------------------- +static void ikcp_ack_push(ikcpcb *kcp, IUINT32 sn, IUINT32 ts) +{ + IUINT32 newsize = kcp->ackcount + 1; + IUINT32 *ptr; + + if (newsize > kcp->ackblock) { + IUINT32 *acklist; + IUINT32 newblock; + + for (newblock = 8; newblock < newsize; newblock <<= 1); + acklist = (IUINT32*)ikcp_malloc(newblock * sizeof(IUINT32) * 2); + + if (acklist == NULL) { + assert(acklist != NULL); + abort(); + } + + if (kcp->acklist != NULL) { + IUINT32 x; + for (x = 0; x < kcp->ackcount; x++) { + acklist[x * 2 + 0] = kcp->acklist[x * 2 + 0]; + acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1]; + } + ikcp_free(kcp->acklist); + } + + kcp->acklist = acklist; + kcp->ackblock = newblock; + } + + ptr = &kcp->acklist[kcp->ackcount * 2]; + ptr[0] = sn; + ptr[1] = ts; + kcp->ackcount++; +} + +static void ikcp_ack_get(const ikcpcb *kcp, int p, IUINT32 *sn, IUINT32 *ts) +{ + if (sn) sn[0] = kcp->acklist[p * 2 + 0]; + if (ts) ts[0] = kcp->acklist[p * 2 + 1]; +} + + +//--------------------------------------------------------------------- +// parse data +//--------------------------------------------------------------------- +void ikcp_parse_data(ikcpcb *kcp, IKCPSEG *newseg) +{ + struct IQUEUEHEAD *p, *prev; + IUINT32 sn = newseg->sn; + int repeat = 0; + + if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) >= 0 || + _itimediff(sn, kcp->rcv_nxt) < 0) { + ikcp_segment_delete(kcp, newseg); + return; + } + + for (p = kcp->rcv_buf.prev; p != &kcp->rcv_buf; p = prev) { + IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); + prev = p->prev; + if (seg->sn == sn) { + repeat = 1; + break; + } + if (_itimediff(sn, seg->sn) > 0) { + break; + } + } + + if (repeat == 0) { + iqueue_init(&newseg->node); + iqueue_add(&newseg->node, p); + kcp->nrcv_buf++; + } else { + ikcp_segment_delete(kcp, newseg); + } + +#if 0 + ikcp_qprint("rcvbuf", &kcp->rcv_buf); + printf("rcv_nxt=%lu\n", kcp->rcv_nxt); +#endif + + // move available data from rcv_buf -> rcv_queue + while (! iqueue_is_empty(&kcp->rcv_buf)) { + IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); + if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { + iqueue_del(&seg->node); + kcp->nrcv_buf--; + iqueue_add_tail(&seg->node, &kcp->rcv_queue); + kcp->nrcv_que++; + kcp->rcv_nxt++; + } else { + break; + } + } + +#if 0 + ikcp_qprint("queue", &kcp->rcv_queue); + printf("rcv_nxt=%lu\n", kcp->rcv_nxt); +#endif + +#if 1 +// printf("snd(buf=%d, queue=%d)\n", kcp->nsnd_buf, kcp->nsnd_que); +// printf("rcv(buf=%d, queue=%d)\n", kcp->nrcv_buf, kcp->nrcv_que); +#endif +} + + +//--------------------------------------------------------------------- +// input data +//--------------------------------------------------------------------- +int ikcp_input(ikcpcb *kcp, const char *data, long size) +{ + IUINT32 prev_una = kcp->snd_una; + IUINT32 maxack = 0, latest_ts = 0; + int flag = 0; + + if (ikcp_canlog(kcp, IKCP_LOG_INPUT)) { + ikcp_log(kcp, IKCP_LOG_INPUT, "[RI] %d bytes", (int)size); + } + + if (data == NULL || (int)size < (int)IKCP_OVERHEAD) return -1; + + while (1) { + IUINT32 ts, sn, len, una, conv; + IUINT16 wnd; + IUINT8 cmd, frg; + IKCPSEG *seg; + + if (size < (int)IKCP_OVERHEAD) break; + + data = ikcp_decode32u(data, &conv); + if (conv != kcp->conv) return -1; + + data = ikcp_decode8u(data, &cmd); + data = ikcp_decode8u(data, &frg); + data = ikcp_decode16u(data, &wnd); + data = ikcp_decode32u(data, &ts); + data = ikcp_decode32u(data, &sn); + data = ikcp_decode32u(data, &una); + data = ikcp_decode32u(data, &len); + + size -= IKCP_OVERHEAD; + + if ((long)size < (long)len || (int)len < 0) return -2; + + if (cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK && + cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS) + return -3; + + kcp->rmt_wnd = wnd; + ikcp_parse_una(kcp, una); + ikcp_shrink_buf(kcp); + + if (cmd == IKCP_CMD_ACK) { + if (_itimediff(kcp->current, ts) >= 0) { + ikcp_update_ack(kcp, _itimediff(kcp->current, ts)); + } + ikcp_parse_ack(kcp, sn); + ikcp_shrink_buf(kcp); + if (flag == 0) { + flag = 1; + maxack = sn; + latest_ts = ts; + } else { + if (_itimediff(sn, maxack) > 0) { + #ifndef IKCP_FASTACK_CONSERVE + maxack = sn; + latest_ts = ts; + #else + if (_itimediff(ts, latest_ts) > 0) { + maxack = sn; + latest_ts = ts; + } + #endif + } + } + if (ikcp_canlog(kcp, IKCP_LOG_IN_ACK)) { + ikcp_log(kcp, IKCP_LOG_IN_ACK, + "input ack: sn=%lu rtt=%ld rto=%ld", (unsigned long)sn, + (long)_itimediff(kcp->current, ts), + (long)kcp->rx_rto); + } + } + else if (cmd == IKCP_CMD_PUSH) { + if (ikcp_canlog(kcp, IKCP_LOG_IN_DATA)) { + ikcp_log(kcp, IKCP_LOG_IN_DATA, + "input psh: sn=%lu ts=%lu", (unsigned long)sn, (unsigned long)ts); + } + if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) < 0) { + ikcp_ack_push(kcp, sn, ts); + if (_itimediff(sn, kcp->rcv_nxt) >= 0) { + seg = ikcp_segment_new(kcp, len); + seg->conv = conv; + seg->cmd = cmd; + seg->frg = frg; + seg->wnd = wnd; + seg->ts = ts; + seg->sn = sn; + seg->una = una; + seg->len = len; + + if (len > 0) { + memcpy(seg->data, data, len); + } + + ikcp_parse_data(kcp, seg); + } + } + } + else if (cmd == IKCP_CMD_WASK) { + // ready to send back IKCP_CMD_WINS in ikcp_flush + // tell remote my window size + kcp->probe |= IKCP_ASK_TELL; + if (ikcp_canlog(kcp, IKCP_LOG_IN_PROBE)) { + ikcp_log(kcp, IKCP_LOG_IN_PROBE, "input probe"); + } + } + else if (cmd == IKCP_CMD_WINS) { + // do nothing + if (ikcp_canlog(kcp, IKCP_LOG_IN_WINS)) { + ikcp_log(kcp, IKCP_LOG_IN_WINS, + "input wins: %lu", (unsigned long)(wnd)); + } + } + else { + return -3; + } + + data += len; + size -= len; + } + + if (flag != 0) { + ikcp_parse_fastack(kcp, maxack, latest_ts); + } + + if (_itimediff(kcp->snd_una, prev_una) > 0) { + if (kcp->cwnd < kcp->rmt_wnd) { + IUINT32 mss = kcp->mss; + if (kcp->cwnd < kcp->ssthresh) { + kcp->cwnd++; + kcp->incr += mss; + } else { + if (kcp->incr < mss) kcp->incr = mss; + kcp->incr += (mss * mss) / kcp->incr + (mss / 16); + if ((kcp->cwnd + 1) * mss <= kcp->incr) { + #if 1 + kcp->cwnd = (kcp->incr + mss - 1) / ((mss > 0)? mss : 1); + #else + kcp->cwnd++; + #endif + } + } + if (kcp->cwnd > kcp->rmt_wnd) { + kcp->cwnd = kcp->rmt_wnd; + kcp->incr = kcp->rmt_wnd * mss; + } + } + } + + return 0; +} + + +//--------------------------------------------------------------------- +// ikcp_encode_seg +//--------------------------------------------------------------------- +static char *ikcp_encode_seg(char *ptr, const IKCPSEG *seg) +{ + ptr = ikcp_encode32u(ptr, seg->conv); + ptr = ikcp_encode8u(ptr, (IUINT8)seg->cmd); + ptr = ikcp_encode8u(ptr, (IUINT8)seg->frg); + ptr = ikcp_encode16u(ptr, (IUINT16)seg->wnd); + ptr = ikcp_encode32u(ptr, seg->ts); + ptr = ikcp_encode32u(ptr, seg->sn); + ptr = ikcp_encode32u(ptr, seg->una); + ptr = ikcp_encode32u(ptr, seg->len); + return ptr; +} + +static int ikcp_wnd_unused(const ikcpcb *kcp) +{ + if (kcp->nrcv_que < kcp->rcv_wnd) { + return kcp->rcv_wnd - kcp->nrcv_que; + } + return 0; +} + + +//--------------------------------------------------------------------- +// ikcp_flush +//--------------------------------------------------------------------- +void ikcp_flush(ikcpcb *kcp) +{ + IUINT32 current = kcp->current; + char *buffer = kcp->buffer; + char *ptr = buffer; + int count, size, i; + IUINT32 resent, cwnd; + IUINT32 rtomin; + struct IQUEUEHEAD *p; + int change = 0; + int lost = 0; + IKCPSEG seg; + + // 'ikcp_update' haven't been called. + if (kcp->updated == 0) return; + + seg.conv = kcp->conv; + seg.cmd = IKCP_CMD_ACK; + seg.frg = 0; + seg.wnd = ikcp_wnd_unused(kcp); + seg.una = kcp->rcv_nxt; + seg.len = 0; + seg.sn = 0; + seg.ts = 0; + + // flush acknowledges + count = kcp->ackcount; + for (i = 0; i < count; i++) { + size = (int)(ptr - buffer); + if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { + ikcp_output(kcp, buffer, size); + ptr = buffer; + } + ikcp_ack_get(kcp, i, &seg.sn, &seg.ts); + ptr = ikcp_encode_seg(ptr, &seg); + } + + kcp->ackcount = 0; + + // probe window size (if remote window size equals zero) + if (kcp->rmt_wnd == 0) { + if (kcp->probe_wait == 0) { + kcp->probe_wait = IKCP_PROBE_INIT; + kcp->ts_probe = kcp->current + kcp->probe_wait; + } + else { + if (_itimediff(kcp->current, kcp->ts_probe) >= 0) { + if (kcp->probe_wait < IKCP_PROBE_INIT) + kcp->probe_wait = IKCP_PROBE_INIT; + kcp->probe_wait += kcp->probe_wait / 2; + if (kcp->probe_wait > IKCP_PROBE_LIMIT) + kcp->probe_wait = IKCP_PROBE_LIMIT; + kcp->ts_probe = kcp->current + kcp->probe_wait; + kcp->probe |= IKCP_ASK_SEND; + } + } + } else { + kcp->ts_probe = 0; + kcp->probe_wait = 0; + } + + // flush window probing commands + if (kcp->probe & IKCP_ASK_SEND) { + seg.cmd = IKCP_CMD_WASK; + size = (int)(ptr - buffer); + if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { + ikcp_output(kcp, buffer, size); + ptr = buffer; + } + ptr = ikcp_encode_seg(ptr, &seg); + } + + // flush window probing commands + if (kcp->probe & IKCP_ASK_TELL) { + seg.cmd = IKCP_CMD_WINS; + size = (int)(ptr - buffer); + if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { + ikcp_output(kcp, buffer, size); + ptr = buffer; + } + ptr = ikcp_encode_seg(ptr, &seg); + } + + kcp->probe = 0; + + // calculate window size + cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd); + if (kcp->nocwnd == 0) cwnd = _imin_(kcp->cwnd, cwnd); + + // move data from snd_queue to snd_buf + while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) { + IKCPSEG *newseg; + if (iqueue_is_empty(&kcp->snd_queue)) break; + + newseg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); + + iqueue_del(&newseg->node); + iqueue_add_tail(&newseg->node, &kcp->snd_buf); + kcp->nsnd_que--; + kcp->nsnd_buf++; + + newseg->conv = kcp->conv; + newseg->cmd = IKCP_CMD_PUSH; + newseg->wnd = seg.wnd; + newseg->ts = current; + newseg->sn = kcp->snd_nxt++; + newseg->una = kcp->rcv_nxt; + newseg->resendts = current; + newseg->rto = kcp->rx_rto; + newseg->fastack = 0; + newseg->xmit = 0; + } + + // calculate resent + resent = (kcp->fastresend > 0)? (IUINT32)kcp->fastresend : 0xffffffff; + rtomin = (kcp->nodelay == 0)? (kcp->rx_rto >> 3) : 0; + + // flush data segments + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { + IKCPSEG *segment = iqueue_entry(p, IKCPSEG, node); + int needsend = 0; + if (segment->xmit == 0) { + needsend = 1; + segment->xmit++; + segment->rto = kcp->rx_rto; + segment->resendts = current + segment->rto + rtomin; + } + else if (_itimediff(current, segment->resendts) >= 0) { + needsend = 1; + segment->xmit++; + kcp->xmit++; + if (kcp->nodelay == 0) { + segment->rto += _imax_(segment->rto, (IUINT32)kcp->rx_rto); + } else { + IINT32 step = (kcp->nodelay < 2)? + ((IINT32)(segment->rto)) : kcp->rx_rto; + segment->rto += step / 2; + } + segment->resendts = current + segment->rto; + lost = 1; + } + else if (segment->fastack >= resent) { + if ((int)segment->xmit <= kcp->fastlimit || + kcp->fastlimit <= 0) { + needsend = 1; + segment->xmit++; + segment->fastack = 0; + segment->resendts = current + segment->rto; + change++; + } + } + + if (needsend) { + int need; + segment->ts = current; + segment->wnd = seg.wnd; + segment->una = kcp->rcv_nxt; + + size = (int)(ptr - buffer); + need = IKCP_OVERHEAD + segment->len; + + if (size + need > (int)kcp->mtu) { + ikcp_output(kcp, buffer, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, segment); + + if (segment->len > 0) { + memcpy(ptr, segment->data, segment->len); + ptr += segment->len; + } + + if (segment->xmit >= kcp->dead_link) { + kcp->state = (IUINT32)-1; + } + } + } + + // flash remain segments + size = (int)(ptr - buffer); + if (size > 0) { + ikcp_output(kcp, buffer, size); + } + + // update ssthresh + if (change) { + IUINT32 inflight = kcp->snd_nxt - kcp->snd_una; + kcp->ssthresh = inflight / 2; + if (kcp->ssthresh < IKCP_THRESH_MIN) + kcp->ssthresh = IKCP_THRESH_MIN; + kcp->cwnd = kcp->ssthresh + resent; + kcp->incr = kcp->cwnd * kcp->mss; + } + + if (lost) { + kcp->ssthresh = cwnd / 2; + if (kcp->ssthresh < IKCP_THRESH_MIN) + kcp->ssthresh = IKCP_THRESH_MIN; + kcp->cwnd = 1; + kcp->incr = kcp->mss; + } + + if (kcp->cwnd < 1) { + kcp->cwnd = 1; + kcp->incr = kcp->mss; + } +} + + +//--------------------------------------------------------------------- +// update state (call it repeatedly, every 10ms-100ms), or you can ask +// ikcp_check when to call it again (without ikcp_input/_send calling). +// 'current' - current timestamp in millisec. +//--------------------------------------------------------------------- +void ikcp_update(ikcpcb *kcp, IUINT32 current) +{ + IINT32 slap; + + kcp->current = current; + + if (kcp->updated == 0) { + kcp->updated = 1; + kcp->ts_flush = kcp->current; + } + + slap = _itimediff(kcp->current, kcp->ts_flush); + + if (slap >= 10000 || slap < -10000) { + kcp->ts_flush = kcp->current; + slap = 0; + } + + if (slap >= 0) { + kcp->ts_flush += kcp->interval; + if (_itimediff(kcp->current, kcp->ts_flush) >= 0) { + kcp->ts_flush = kcp->current + kcp->interval; + } + ikcp_flush(kcp); + } +} + + +//--------------------------------------------------------------------- +// Determine when should you invoke ikcp_update: +// returns when you should invoke ikcp_update in millisec, if there +// is no ikcp_input/_send calling. you can call ikcp_update in that +// time, instead of call update repeatly. +// Important to reduce unnacessary ikcp_update invoking. use it to +// schedule ikcp_update (eg. implementing an epoll-like mechanism, +// or optimize ikcp_update when handling massive kcp connections) +//--------------------------------------------------------------------- +IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current) +{ + IUINT32 ts_flush = kcp->ts_flush; + IINT32 tm_flush = 0x7fffffff; + IINT32 tm_packet = 0x7fffffff; + IUINT32 minimal = 0; + struct IQUEUEHEAD *p; + + if (kcp->updated == 0) { + return current; + } + + if (_itimediff(current, ts_flush) >= 10000 || + _itimediff(current, ts_flush) < -10000) { + ts_flush = current; + } + + if (_itimediff(current, ts_flush) >= 0) { + return current; + } + + tm_flush = _itimediff(ts_flush, current); + + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { + const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); + IINT32 diff = _itimediff(seg->resendts, current); + if (diff <= 0) { + return current; + } + if (diff < tm_packet) tm_packet = diff; + } + + minimal = (IUINT32)(tm_packet < tm_flush ? tm_packet : tm_flush); + if (minimal >= kcp->interval) minimal = kcp->interval; + + return current + minimal; +} + + + +int ikcp_setmtu(ikcpcb *kcp, int mtu) +{ + char *buffer; + if (mtu < 50 || mtu < (int)IKCP_OVERHEAD) + return -1; + buffer = (char*)ikcp_malloc((mtu + IKCP_OVERHEAD) * 3); + if (buffer == NULL) + return -2; + kcp->mtu = mtu; + kcp->mss = kcp->mtu - IKCP_OVERHEAD; + ikcp_free(kcp->buffer); + kcp->buffer = buffer; + return 0; +} + +int ikcp_interval(ikcpcb *kcp, int interval) +{ + if (interval > 5000) interval = 5000; + else if (interval < 10) interval = 10; + kcp->interval = interval; + return 0; +} + +int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc) +{ + if (nodelay >= 0) { + kcp->nodelay = nodelay; + if (nodelay) { + kcp->rx_minrto = IKCP_RTO_NDL; + } + else { + kcp->rx_minrto = IKCP_RTO_MIN; + } + } + if (interval >= 0) { + if (interval > 5000) interval = 5000; + else if (interval < 10) interval = 10; + kcp->interval = interval; + } + if (resend >= 0) { + kcp->fastresend = resend; + } + if (nc >= 0) { + kcp->nocwnd = nc; + } + return 0; +} + + +int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd) +{ + if (kcp) { + if (sndwnd > 0) { + kcp->snd_wnd = sndwnd; + } + if (rcvwnd > 0) { // must >= max fragment size + kcp->rcv_wnd = _imax_(rcvwnd, IKCP_WND_RCV); + } + } + return 0; +} + +int ikcp_waitsnd(const ikcpcb *kcp) +{ + return kcp->nsnd_buf + kcp->nsnd_que; +} + + +// read conv +IUINT32 ikcp_getconv(const void *ptr) +{ + IUINT32 conv; + ikcp_decode32u((const char*)ptr, &conv); + return conv; +} + + diff --git a/NativeLibs/yasio/kcp/ikcp.h b/NativeLibs/yasio/3rdparty/kcp/ikcp.h similarity index 96% rename from NativeLibs/yasio/kcp/ikcp.h rename to NativeLibs/yasio/3rdparty/kcp/ikcp.h index b8c337f..e525105 100644 --- a/NativeLibs/yasio/kcp/ikcp.h +++ b/NativeLibs/yasio/3rdparty/kcp/ikcp.h @@ -1,416 +1,416 @@ -//===================================================================== -// -// KCP - A Better ARQ Protocol Implementation -// skywind3000 (at) gmail.com, 2010-2011 -// -// Features: -// + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. -// + Maximum RTT reduce three times vs tcp. -// + Lightweight, distributed as a single source file. -// -//===================================================================== -#ifndef __IKCP_H__ -#define __IKCP_H__ - -#include -#include -#include - - -//===================================================================== -// 32BIT INTEGER DEFINITION -//===================================================================== -#ifndef __INTEGER_32_BITS__ -#define __INTEGER_32_BITS__ -#if defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ - defined(_M_AMD64) - typedef unsigned int ISTDUINT32; - typedef int ISTDINT32; -#elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ - defined(__i386) || defined(_M_X86) - typedef unsigned long ISTDUINT32; - typedef long ISTDINT32; -#elif defined(__MACOS__) - typedef UInt32 ISTDUINT32; - typedef SInt32 ISTDINT32; -#elif defined(__APPLE__) && defined(__MACH__) - #include - typedef u_int32_t ISTDUINT32; - typedef int32_t ISTDINT32; -#elif defined(__BEOS__) - #include - typedef u_int32_t ISTDUINT32; - typedef int32_t ISTDINT32; -#elif (defined(_MSC_VER) || defined(__BORLANDC__)) && (!defined(__MSDOS__)) - typedef unsigned __int32 ISTDUINT32; - typedef __int32 ISTDINT32; -#elif defined(__GNUC__) - #include - typedef uint32_t ISTDUINT32; - typedef int32_t ISTDINT32; -#else - typedef unsigned long ISTDUINT32; - typedef long ISTDINT32; -#endif -#endif - - -//===================================================================== -// Integer Definition -//===================================================================== -#ifndef __IINT8_DEFINED -#define __IINT8_DEFINED -typedef char IINT8; -#endif - -#ifndef __IUINT8_DEFINED -#define __IUINT8_DEFINED -typedef unsigned char IUINT8; -#endif - -#ifndef __IUINT16_DEFINED -#define __IUINT16_DEFINED -typedef unsigned short IUINT16; -#endif - -#ifndef __IINT16_DEFINED -#define __IINT16_DEFINED -typedef short IINT16; -#endif - -#ifndef __IINT32_DEFINED -#define __IINT32_DEFINED -typedef ISTDINT32 IINT32; -#endif - -#ifndef __IUINT32_DEFINED -#define __IUINT32_DEFINED -typedef ISTDUINT32 IUINT32; -#endif - -#ifndef __IINT64_DEFINED -#define __IINT64_DEFINED -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 IINT64; -#else -typedef long long IINT64; -#endif -#endif - -#ifndef __IUINT64_DEFINED -#define __IUINT64_DEFINED -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef unsigned __int64 IUINT64; -#else -typedef unsigned long long IUINT64; -#endif -#endif - -#ifndef INLINE -#if defined(__GNUC__) - -#if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) -#define INLINE __inline__ __attribute__((always_inline)) -#else -#define INLINE __inline__ -#endif - -#elif (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)) -#define INLINE __inline -#else -#define INLINE -#endif -#endif - -#if (!defined(__cplusplus)) && (!defined(inline)) -#define inline INLINE -#endif - - -//===================================================================== -// QUEUE DEFINITION -//===================================================================== -#ifndef __IQUEUE_DEF__ -#define __IQUEUE_DEF__ - -struct IQUEUEHEAD { - struct IQUEUEHEAD *next, *prev; -}; - -typedef struct IQUEUEHEAD iqueue_head; - - -//--------------------------------------------------------------------- -// queue init -//--------------------------------------------------------------------- -#define IQUEUE_HEAD_INIT(name) { &(name), &(name) } -#define IQUEUE_HEAD(name) \ - struct IQUEUEHEAD name = IQUEUE_HEAD_INIT(name) - -#define IQUEUE_INIT(ptr) ( \ - (ptr)->next = (ptr), (ptr)->prev = (ptr)) - -#define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -#define ICONTAINEROF(ptr, type, member) ( \ - (type*)( ((char*)((type*)ptr)) - IOFFSETOF(type, member)) ) - -#define IQUEUE_ENTRY(ptr, type, member) ICONTAINEROF(ptr, type, member) - - -//--------------------------------------------------------------------- -// queue operation -//--------------------------------------------------------------------- -#define IQUEUE_ADD(node, head) ( \ - (node)->prev = (head), (node)->next = (head)->next, \ - (head)->next->prev = (node), (head)->next = (node)) - -#define IQUEUE_ADD_TAIL(node, head) ( \ - (node)->prev = (head)->prev, (node)->next = (head), \ - (head)->prev->next = (node), (head)->prev = (node)) - -#define IQUEUE_DEL_BETWEEN(p, n) ((n)->prev = (p), (p)->next = (n)) - -#define IQUEUE_DEL(entry) (\ - (entry)->next->prev = (entry)->prev, \ - (entry)->prev->next = (entry)->next, \ - (entry)->next = 0, (entry)->prev = 0) - -#define IQUEUE_DEL_INIT(entry) do { \ - IQUEUE_DEL(entry); IQUEUE_INIT(entry); } while (0) - -#define IQUEUE_IS_EMPTY(entry) ((entry) == (entry)->next) - -#define iqueue_init IQUEUE_INIT -#define iqueue_entry IQUEUE_ENTRY -#define iqueue_add IQUEUE_ADD -#define iqueue_add_tail IQUEUE_ADD_TAIL -#define iqueue_del IQUEUE_DEL -#define iqueue_del_init IQUEUE_DEL_INIT -#define iqueue_is_empty IQUEUE_IS_EMPTY - -#define IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) \ - for ((iterator) = iqueue_entry((head)->next, TYPE, MEMBER); \ - &((iterator)->MEMBER) != (head); \ - (iterator) = iqueue_entry((iterator)->MEMBER.next, TYPE, MEMBER)) - -#define iqueue_foreach(iterator, head, TYPE, MEMBER) \ - IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) - -#define iqueue_foreach_entry(pos, head) \ - for( (pos) = (head)->next; (pos) != (head) ; (pos) = (pos)->next ) - - -#define __iqueue_splice(list, head) do { \ - iqueue_head *first = (list)->next, *last = (list)->prev; \ - iqueue_head *at = (head)->next; \ - (first)->prev = (head), (head)->next = (first); \ - (last)->next = (at), (at)->prev = (last); } while (0) - -#define iqueue_splice(list, head) do { \ - if (!iqueue_is_empty(list)) __iqueue_splice(list, head); } while (0) - -#define iqueue_splice_init(list, head) do { \ - iqueue_splice(list, head); iqueue_init(list); } while (0) - - -#ifdef _MSC_VER -#pragma warning(disable:4311) -#pragma warning(disable:4312) -#pragma warning(disable:4996) -#endif - -#endif - - -//--------------------------------------------------------------------- -// BYTE ORDER & ALIGNMENT -//--------------------------------------------------------------------- -#ifndef IWORDS_BIG_ENDIAN - #ifdef _BIG_ENDIAN_ - #if _BIG_ENDIAN_ - #define IWORDS_BIG_ENDIAN 1 - #endif - #endif - #ifndef IWORDS_BIG_ENDIAN - #if defined(__hppa__) || \ - defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ - (defined(__MIPS__) && defined(__MIPSEB__)) || \ - defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ - defined(__sparc__) || defined(__powerpc__) || \ - defined(__mc68000__) || defined(__s390x__) || defined(__s390__) - #define IWORDS_BIG_ENDIAN 1 - #endif - #endif - #ifndef IWORDS_BIG_ENDIAN - #define IWORDS_BIG_ENDIAN 0 - #endif -#endif - -#ifndef IWORDS_MUST_ALIGN - #if defined(__i386__) || defined(__i386) || defined(_i386_) - #define IWORDS_MUST_ALIGN 0 - #elif defined(_M_IX86) || defined(_X86_) || defined(__x86_64__) - #define IWORDS_MUST_ALIGN 0 - #elif defined(__amd64) || defined(__amd64__) - #define IWORDS_MUST_ALIGN 0 - #else - #define IWORDS_MUST_ALIGN 1 - #endif -#endif - - -//===================================================================== -// SEGMENT -//===================================================================== -struct IKCPSEG -{ - struct IQUEUEHEAD node; - IUINT32 conv; - IUINT32 cmd; - IUINT32 frg; - IUINT32 wnd; - IUINT32 ts; - IUINT32 sn; - IUINT32 una; - IUINT32 len; - IUINT32 resendts; - IUINT32 rto; - IUINT32 fastack; - IUINT32 xmit; - char data[1]; -}; - - -//--------------------------------------------------------------------- -// IKCPCB -//--------------------------------------------------------------------- -struct IKCPCB -{ - IUINT32 conv, mtu, mss, state; - IUINT32 snd_una, snd_nxt, rcv_nxt; - IUINT32 ts_recent, ts_lastack, ssthresh; - IINT32 rx_rttval, rx_srtt, rx_rto, rx_minrto; - IUINT32 snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe; - IUINT32 current, interval, ts_flush, xmit; - IUINT32 nrcv_buf, nsnd_buf; - IUINT32 nrcv_que, nsnd_que; - IUINT32 nodelay, updated; - IUINT32 ts_probe, probe_wait; - IUINT32 dead_link, incr; - struct IQUEUEHEAD snd_queue; - struct IQUEUEHEAD rcv_queue; - struct IQUEUEHEAD snd_buf; - struct IQUEUEHEAD rcv_buf; - IUINT32 *acklist; - IUINT32 ackcount; - IUINT32 ackblock; - void *user; - char *buffer; - int fastresend; - int fastlimit; - int nocwnd, stream; - int logmask; - int (*output)(const char *buf, int len, struct IKCPCB *kcp, void *user); - void (*writelog)(const char *log, struct IKCPCB *kcp, void *user); -}; - - -typedef struct IKCPCB ikcpcb; - -#define IKCP_LOG_OUTPUT 1 -#define IKCP_LOG_INPUT 2 -#define IKCP_LOG_SEND 4 -#define IKCP_LOG_RECV 8 -#define IKCP_LOG_IN_DATA 16 -#define IKCP_LOG_IN_ACK 32 -#define IKCP_LOG_IN_PROBE 64 -#define IKCP_LOG_IN_WINS 128 -#define IKCP_LOG_OUT_DATA 256 -#define IKCP_LOG_OUT_ACK 512 -#define IKCP_LOG_OUT_PROBE 1024 -#define IKCP_LOG_OUT_WINS 2048 - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------- -// interface -//--------------------------------------------------------------------- - -// create a new kcp control object, 'conv' must equal in two endpoint -// from the same connection. 'user' will be passed to the output callback -// output callback can be setup like this: 'kcp->output = my_udp_output' -ikcpcb* ikcp_create(IUINT32 conv, void *user); - -// release kcp control object -void ikcp_release(ikcpcb *kcp); - -// set output callback, which will be invoked by kcp -void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, - ikcpcb *kcp, void *user)); - -// user/upper level recv: returns size, returns below zero for EAGAIN -int ikcp_recv(ikcpcb *kcp, char *buffer, int len); - -// user/upper level send, returns below zero for error -int ikcp_send(ikcpcb *kcp, const char *buffer, int len); - -// update state (call it repeatedly, every 10ms-100ms), or you can ask -// ikcp_check when to call it again (without ikcp_input/_send calling). -// 'current' - current timestamp in millisec. -void ikcp_update(ikcpcb *kcp, IUINT32 current); - -// Determine when should you invoke ikcp_update: -// returns when you should invoke ikcp_update in millisec, if there -// is no ikcp_input/_send calling. you can call ikcp_update in that -// time, instead of call update repeatly. -// Important to reduce unnacessary ikcp_update invoking. use it to -// schedule ikcp_update (eg. implementing an epoll-like mechanism, -// or optimize ikcp_update when handling massive kcp connections) -IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current); - -// when you received a low level packet (eg. UDP packet), call it -int ikcp_input(ikcpcb *kcp, const char *data, long size); - -// flush pending data -void ikcp_flush(ikcpcb *kcp); - -// check the size of next message in the recv queue -int ikcp_peeksize(const ikcpcb *kcp); - -// change MTU size, default is 1400 -int ikcp_setmtu(ikcpcb *kcp, int mtu); - -// set maximum window size: sndwnd=32, rcvwnd=32 by default -int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd); - -// get how many packet is waiting to be sent -int ikcp_waitsnd(const ikcpcb *kcp); - -// fastest: ikcp_nodelay(kcp, 1, 20, 2, 1) -// nodelay: 0:disable(default), 1:enable -// interval: internal update timer interval in millisec, default is 100ms -// resend: 0:disable fast resend(default), 1:enable fast resend -// nc: 0:normal congestion control(default), 1:disable congestion control -int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc); - - -void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...); - -// setup allocator -void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)); - -// read conv -IUINT32 ikcp_getconv(const void *ptr); - - -#ifdef __cplusplus -} -#endif - -#endif - - +//===================================================================== +// +// KCP - A Better ARQ Protocol Implementation +// skywind3000 (at) gmail.com, 2010-2011 +// +// Features: +// + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. +// + Maximum RTT reduce three times vs tcp. +// + Lightweight, distributed as a single source file. +// +//===================================================================== +#ifndef __IKCP_H__ +#define __IKCP_H__ + +#include +#include +#include + + +//===================================================================== +// 32BIT INTEGER DEFINITION +//===================================================================== +#ifndef __INTEGER_32_BITS__ +#define __INTEGER_32_BITS__ +#if defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ + defined(_M_AMD64) + typedef unsigned int ISTDUINT32; + typedef int ISTDINT32; +#elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ + defined(__i386) || defined(_M_X86) + typedef unsigned long ISTDUINT32; + typedef long ISTDINT32; +#elif defined(__MACOS__) + typedef UInt32 ISTDUINT32; + typedef SInt32 ISTDINT32; +#elif defined(__APPLE__) && defined(__MACH__) + #include + typedef u_int32_t ISTDUINT32; + typedef int32_t ISTDINT32; +#elif defined(__BEOS__) + #include + typedef u_int32_t ISTDUINT32; + typedef int32_t ISTDINT32; +#elif (defined(_MSC_VER) || defined(__BORLANDC__)) && (!defined(__MSDOS__)) + typedef unsigned __int32 ISTDUINT32; + typedef __int32 ISTDINT32; +#elif defined(__GNUC__) + #include + typedef uint32_t ISTDUINT32; + typedef int32_t ISTDINT32; +#else + typedef unsigned long ISTDUINT32; + typedef long ISTDINT32; +#endif +#endif + + +//===================================================================== +// Integer Definition +//===================================================================== +#ifndef __IINT8_DEFINED +#define __IINT8_DEFINED +typedef char IINT8; +#endif + +#ifndef __IUINT8_DEFINED +#define __IUINT8_DEFINED +typedef unsigned char IUINT8; +#endif + +#ifndef __IUINT16_DEFINED +#define __IUINT16_DEFINED +typedef unsigned short IUINT16; +#endif + +#ifndef __IINT16_DEFINED +#define __IINT16_DEFINED +typedef short IINT16; +#endif + +#ifndef __IINT32_DEFINED +#define __IINT32_DEFINED +typedef ISTDINT32 IINT32; +#endif + +#ifndef __IUINT32_DEFINED +#define __IUINT32_DEFINED +typedef ISTDUINT32 IUINT32; +#endif + +#ifndef __IINT64_DEFINED +#define __IINT64_DEFINED +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 IINT64; +#else +typedef long long IINT64; +#endif +#endif + +#ifndef __IUINT64_DEFINED +#define __IUINT64_DEFINED +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 IUINT64; +#else +typedef unsigned long long IUINT64; +#endif +#endif + +#ifndef INLINE +#if defined(__GNUC__) + +#if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) +#define INLINE __inline__ __attribute__((always_inline)) +#else +#define INLINE __inline__ +#endif + +#elif (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)) +#define INLINE __inline +#else +#define INLINE +#endif +#endif + +#if (!defined(__cplusplus)) && (!defined(inline)) +#define inline INLINE +#endif + + +//===================================================================== +// QUEUE DEFINITION +//===================================================================== +#ifndef __IQUEUE_DEF__ +#define __IQUEUE_DEF__ + +struct IQUEUEHEAD { + struct IQUEUEHEAD *next, *prev; +}; + +typedef struct IQUEUEHEAD iqueue_head; + + +//--------------------------------------------------------------------- +// queue init +//--------------------------------------------------------------------- +#define IQUEUE_HEAD_INIT(name) { &(name), &(name) } +#define IQUEUE_HEAD(name) \ + struct IQUEUEHEAD name = IQUEUE_HEAD_INIT(name) + +#define IQUEUE_INIT(ptr) ( \ + (ptr)->next = (ptr), (ptr)->prev = (ptr)) + +#define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#define ICONTAINEROF(ptr, type, member) ( \ + (type*)( ((char*)((type*)ptr)) - IOFFSETOF(type, member)) ) + +#define IQUEUE_ENTRY(ptr, type, member) ICONTAINEROF(ptr, type, member) + + +//--------------------------------------------------------------------- +// queue operation +//--------------------------------------------------------------------- +#define IQUEUE_ADD(node, head) ( \ + (node)->prev = (head), (node)->next = (head)->next, \ + (head)->next->prev = (node), (head)->next = (node)) + +#define IQUEUE_ADD_TAIL(node, head) ( \ + (node)->prev = (head)->prev, (node)->next = (head), \ + (head)->prev->next = (node), (head)->prev = (node)) + +#define IQUEUE_DEL_BETWEEN(p, n) ((n)->prev = (p), (p)->next = (n)) + +#define IQUEUE_DEL(entry) (\ + (entry)->next->prev = (entry)->prev, \ + (entry)->prev->next = (entry)->next, \ + (entry)->next = 0, (entry)->prev = 0) + +#define IQUEUE_DEL_INIT(entry) do { \ + IQUEUE_DEL(entry); IQUEUE_INIT(entry); } while (0) + +#define IQUEUE_IS_EMPTY(entry) ((entry) == (entry)->next) + +#define iqueue_init IQUEUE_INIT +#define iqueue_entry IQUEUE_ENTRY +#define iqueue_add IQUEUE_ADD +#define iqueue_add_tail IQUEUE_ADD_TAIL +#define iqueue_del IQUEUE_DEL +#define iqueue_del_init IQUEUE_DEL_INIT +#define iqueue_is_empty IQUEUE_IS_EMPTY + +#define IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) \ + for ((iterator) = iqueue_entry((head)->next, TYPE, MEMBER); \ + &((iterator)->MEMBER) != (head); \ + (iterator) = iqueue_entry((iterator)->MEMBER.next, TYPE, MEMBER)) + +#define iqueue_foreach(iterator, head, TYPE, MEMBER) \ + IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) + +#define iqueue_foreach_entry(pos, head) \ + for( (pos) = (head)->next; (pos) != (head) ; (pos) = (pos)->next ) + + +#define __iqueue_splice(list, head) do { \ + iqueue_head *first = (list)->next, *last = (list)->prev; \ + iqueue_head *at = (head)->next; \ + (first)->prev = (head), (head)->next = (first); \ + (last)->next = (at), (at)->prev = (last); } while (0) + +#define iqueue_splice(list, head) do { \ + if (!iqueue_is_empty(list)) __iqueue_splice(list, head); } while (0) + +#define iqueue_splice_init(list, head) do { \ + iqueue_splice(list, head); iqueue_init(list); } while (0) + + +#ifdef _MSC_VER +#pragma warning(disable:4311) +#pragma warning(disable:4312) +#pragma warning(disable:4996) +#endif + +#endif + + +//--------------------------------------------------------------------- +// BYTE ORDER & ALIGNMENT +//--------------------------------------------------------------------- +#ifndef IWORDS_BIG_ENDIAN + #ifdef _BIG_ENDIAN_ + #if _BIG_ENDIAN_ + #define IWORDS_BIG_ENDIAN 1 + #endif + #endif + #ifndef IWORDS_BIG_ENDIAN + #if defined(__hppa__) || \ + defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ + (defined(__MIPS__) && defined(__MIPSEB__)) || \ + defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ + defined(__sparc__) || defined(__powerpc__) || \ + defined(__mc68000__) || defined(__s390x__) || defined(__s390__) + #define IWORDS_BIG_ENDIAN 1 + #endif + #endif + #ifndef IWORDS_BIG_ENDIAN + #define IWORDS_BIG_ENDIAN 0 + #endif +#endif + +#ifndef IWORDS_MUST_ALIGN + #if defined(__i386__) || defined(__i386) || defined(_i386_) + #define IWORDS_MUST_ALIGN 0 + #elif defined(_M_IX86) || defined(_X86_) || defined(__x86_64__) + #define IWORDS_MUST_ALIGN 0 + #elif defined(__amd64) || defined(__amd64__) + #define IWORDS_MUST_ALIGN 0 + #else + #define IWORDS_MUST_ALIGN 1 + #endif +#endif + + +//===================================================================== +// SEGMENT +//===================================================================== +struct IKCPSEG +{ + struct IQUEUEHEAD node; + IUINT32 conv; + IUINT32 cmd; + IUINT32 frg; + IUINT32 wnd; + IUINT32 ts; + IUINT32 sn; + IUINT32 una; + IUINT32 len; + IUINT32 resendts; + IUINT32 rto; + IUINT32 fastack; + IUINT32 xmit; + char data[1]; +}; + + +//--------------------------------------------------------------------- +// IKCPCB +//--------------------------------------------------------------------- +struct IKCPCB +{ + IUINT32 conv, mtu, mss, state; + IUINT32 snd_una, snd_nxt, rcv_nxt; + IUINT32 ts_recent, ts_lastack, ssthresh; + IINT32 rx_rttval, rx_srtt, rx_rto, rx_minrto; + IUINT32 snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe; + IUINT32 current, interval, ts_flush, xmit; + IUINT32 nrcv_buf, nsnd_buf; + IUINT32 nrcv_que, nsnd_que; + IUINT32 nodelay, updated; + IUINT32 ts_probe, probe_wait; + IUINT32 dead_link, incr; + struct IQUEUEHEAD snd_queue; + struct IQUEUEHEAD rcv_queue; + struct IQUEUEHEAD snd_buf; + struct IQUEUEHEAD rcv_buf; + IUINT32 *acklist; + IUINT32 ackcount; + IUINT32 ackblock; + void *user; + char *buffer; + int fastresend; + int fastlimit; + int nocwnd, stream; + int logmask; + int (*output)(const char *buf, int len, struct IKCPCB *kcp, void *user); + void (*writelog)(const char *log, struct IKCPCB *kcp, void *user); +}; + + +typedef struct IKCPCB ikcpcb; + +#define IKCP_LOG_OUTPUT 1 +#define IKCP_LOG_INPUT 2 +#define IKCP_LOG_SEND 4 +#define IKCP_LOG_RECV 8 +#define IKCP_LOG_IN_DATA 16 +#define IKCP_LOG_IN_ACK 32 +#define IKCP_LOG_IN_PROBE 64 +#define IKCP_LOG_IN_WINS 128 +#define IKCP_LOG_OUT_DATA 256 +#define IKCP_LOG_OUT_ACK 512 +#define IKCP_LOG_OUT_PROBE 1024 +#define IKCP_LOG_OUT_WINS 2048 + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------- +// interface +//--------------------------------------------------------------------- + +// create a new kcp control object, 'conv' must equal in two endpoint +// from the same connection. 'user' will be passed to the output callback +// output callback can be setup like this: 'kcp->output = my_udp_output' +ikcpcb* ikcp_create(IUINT32 conv, void *user); + +// release kcp control object +void ikcp_release(ikcpcb *kcp); + +// set output callback, which will be invoked by kcp +void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, + ikcpcb *kcp, void *user)); + +// user/upper level recv: returns size, returns below zero for EAGAIN +int ikcp_recv(ikcpcb *kcp, char *buffer, int len); + +// user/upper level send, returns below zero for error +int ikcp_send(ikcpcb *kcp, const char *buffer, int len); + +// update state (call it repeatedly, every 10ms-100ms), or you can ask +// ikcp_check when to call it again (without ikcp_input/_send calling). +// 'current' - current timestamp in millisec. +void ikcp_update(ikcpcb *kcp, IUINT32 current); + +// Determine when should you invoke ikcp_update: +// returns when you should invoke ikcp_update in millisec, if there +// is no ikcp_input/_send calling. you can call ikcp_update in that +// time, instead of call update repeatly. +// Important to reduce unnacessary ikcp_update invoking. use it to +// schedule ikcp_update (eg. implementing an epoll-like mechanism, +// or optimize ikcp_update when handling massive kcp connections) +IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current); + +// when you received a low level packet (eg. UDP packet), call it +int ikcp_input(ikcpcb *kcp, const char *data, long size); + +// flush pending data +void ikcp_flush(ikcpcb *kcp); + +// check the size of next message in the recv queue +int ikcp_peeksize(const ikcpcb *kcp); + +// change MTU size, default is 1400 +int ikcp_setmtu(ikcpcb *kcp, int mtu); + +// set maximum window size: sndwnd=32, rcvwnd=32 by default +int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd); + +// get how many packet is waiting to be sent +int ikcp_waitsnd(const ikcpcb *kcp); + +// fastest: ikcp_nodelay(kcp, 1, 20, 2, 1) +// nodelay: 0:disable(default), 1:enable +// interval: internal update timer interval in millisec, default is 100ms +// resend: 0:disable fast resend(default), 1:enable fast resend +// nc: 0:normal congestion control(default), 1:disable congestion control +int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc); + + +void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...); + +// setup allocator +void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)); + +// read conv +IUINT32 ikcp_getconv(const void *ptr); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/NativeLibs/yasio/CMakeLists.txt b/NativeLibs/yasio/CMakeLists.txt index 5589b4a..4e75a3a 100644 --- a/NativeLibs/yasio/CMakeLists.txt +++ b/NativeLibs/yasio/CMakeLists.txt @@ -1,6 +1,6 @@ # A multi-platform support c++11 library with focus on asynchronous socket I/O for any client application. # -# Copyright (c) 2012-2023 HALX99. +# Copyright (c) 2012-2024 HALX99. # # Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://opensource.org/licenses/MIT @@ -18,32 +18,32 @@ cmake_policy(SET CMP0048 NEW) set(yasio_target_name yasio) project(${yasio_target_name}) +set(_1kfetch_cache_dir "${CMAKE_CURRENT_LIST_DIR}/cache" CACHE STRING "" FORCE) +set(_1kfetch_manifest "${CMAKE_CURRENT_LIST_DIR}/manifest.json" CACHE STRING "" FORCE) + +include(1k/platform.cmake) +include(1k/fetch.cmake) include(CMakeDependentOption) -# specify settings for yasio-ni -# cmake_dependent_option(YASIO_BUILD_TESTS -# "Build the tests when we are the root project" ON -# "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) +cmake_dependent_option(YASIO_BUILD_TESTS + "Build the tests when we are the root project" ON + "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) -# cmake_dependent_option(YASIO_BUILD_LUA_EXAMPLE -# "Build lua example when we are the root project" ON -# "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) -set(YASIO_SSL_BACKEND 0) -set(YASIO_ENABLE_HALF_FLOAT OFF) +cmake_dependent_option(YASIO_BUILD_LUA_EXAMPLE + "Build lua example when we are the root project" ON + "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) -option(YASIO_ENABLE_EXT_HTTP "Build yasio http extension" OFF) +option(YASIO_ENABLE_EXT_HTTP "Build yasio http extension" ON) option(YASIO_ENABLE_LUA "Build yasio with lua support" OFF) option(YASIO_ENABLE_AXLUA "Build yasio with axmol-lua support" OFF) -option(YAISO_ENABLE_NI "Build yasio with native interface for interop" ON) -option(YASIO_ENABLE_KCP "Enable kcp support" ON) +option(YASIO_ENABLE_NI "Build yasio with native interface for interop" OFF) +option(YASIO_ENABLE_KCP "Enable kcp support" OFF) option(YASIO_NO_DEPS "Build yasio without deps" OFF) set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(YASIO_ROOT ${CMAKE_CURRENT_LIST_DIR}) - - message(STATUS "YASIO_ROOT=${YASIO_ROOT}") message(STATUS "CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}") message(STATUS "MSVC=${MSVC}, MSVC_IDE=${MSVC_IDE}") @@ -120,11 +120,12 @@ endif() # Auto choose ssl backend if not supplied by user if (NOT DEFINED YASIO_SSL_BACKEND) - # mbedtls can't compile for watchOS, and openssl prebuilt also not ready yet - if ((CMAKE_SYSTEM_NAME STREQUAL "watchOS") OR (CMAKE_SYSTEM_NAME MATCHES "Emscripten")) + if (CMAKE_SYSTEM_NAME MATCHES "Emscripten") set(YASIO_SSL_BACKEND 0) + elseif(CMAKE_SYSTEM_NAME STREQUAL "watchOS") + set(YASIO_SSL_BACKEND 2) # mbedtls else() - set(YASIO_SSL_BACKEND 1) + set(YASIO_SSL_BACKEND 1) # openssl endif() endif() @@ -149,10 +150,10 @@ if (ANDROID) endif() endif() -include_directories( +set(YASIO_INC_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${THIRDPART_INC} + "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty" ) ### no deps @@ -170,13 +171,25 @@ endif() if (YASIO_SSL_BACKEND EQUAL 1) # openssl message(STATUS "Build with openssl support") - add_subdirectory(thirdparty/openssl) + add_subdirectory(3rdparty/openssl) elseif(YASIO_SSL_BACKEND EQUAL 2) # mbedtls message(STATUS "Build with mbedtls support") - include_directories("${PROJECT_SOURCE_DIR}/thirdparty/mbedtls/include") set(ENABLE_PROGRAMS OFF CACHE BOOL "Build mbedtls programs" FORCE) set(ENABLE_TESTING OFF CACHE BOOL "Build mbed TLS tests." FORCE) - add_subdirectory(${PROJECT_SOURCE_DIR}/thirdparty/mbedtls) + set(MBEDTLS_VER "3.4.1") + if(MSVC_VERSION LESS 1900) + message(AUTHOR_WARNING "Using mbedtls 2.28.3 for vs2013 happy") + set(MBEDTLS_VER "2.28.3") + endif() + include(1k/CPM.cmake) + CPMAddPackage( + NAME mbedtls + VERSION ${MBEDTLS_VER} + GITHUB_REPOSITORY "Mbed-TLS/mbedtls" + GIT_TAG "v${MBEDTLS_VER}" + OPTIONS + "MBEDTLS_FATAL_WARNINGS OFF" + ) yasio_config_target_outdir(mbedtls) yasio_config_target_outdir(mbedcrypto) yasio_config_target_outdir(mbedx509) @@ -184,18 +197,23 @@ endif() ### c-ares support if (YASIO_USE_CARES) - add_subdirectory(thirdparty/c-ares) + add_subdirectory(3rdparty/c-ares) endif() ### The yasio core library project file(GLOB YASIO_CORE yasio/*.hpp;yasio/*.cpp;yasio/compiler/*.hpp;yasio/impl/*.hpp;) if (YASIO_ENABLE_KCP) - set(YASIO_CORE ${YASIO_CORE} - ${PROJECT_SOURCE_DIR}/kcp/ikcp.c - ) + if (NOT kcp_SOURCE_DIR) + set(YASIO_CORE ${YASIO_CORE} + ${PROJECT_SOURCE_DIR}/3rdparty/kcp/ikcp.c + ) + list(APPEND YASIO_INC_DIRS "${PROJECT_SOURCE_DIR}/3rdparty/kcp") + else() + list(APPEND THIRDPART_LIB "kcp") + endif() endif() -if (YAISO_ENABLE_NI) +if (YASIO_ENABLE_NI) set(YASIO_CORE ${YASIO_CORE} yasio/bindings/yasio_ni.cpp ) @@ -220,11 +238,11 @@ if(ANDROID AND CARES_INCLUDE_DIR) endif() if(WIN32 AND YASIO_ENABLE_HPERF_IO) - set(THIRDPART_SRC thirdparty/wepoll/wepoll.c) + set(THIRDPART_SRC 3rdparty/wepoll/wepoll.c) endif() -if(YASIO_ENABLE_KCP OR YASIO_ENABLE_LUA OR YASIO_USE_CARES OR YASIO_ENABLE_HALF_FLOAT) - include_directories("${PROJECT_SOURCE_DIR}/thirdparty") +if(YASIO_ENABLE_KCP) + include_directories("${PROJECT_SOURCE_DIR}/3rdparty") endif() macro(source_group_by_dir proj_dir source_files) @@ -294,7 +312,8 @@ else ( ) ) endif ( ) -target_include_directories(${yasio_target_name} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty) +message(STATUS "YASIO_INC_DIRS=${YASIO_INC_DIRS}") +target_include_directories(${yasio_target_name} PUBLIC ${YASIO_INC_DIRS}) if (BUILD_SHARED_LIBS) target_compile_definitions(${yasio_target_name} @@ -410,8 +429,8 @@ if(YASIO_ENABLE_LUA) endif() # link libraries for yasio_core when BUILD_SHARED_LIBS=TRUE +yasio_link_ssl_libraries(${yasio_target_name}) if(BUILD_SHARED_LIBS) - yasio_link_ssl_libraries(${yasio_target_name}) if(NOT WIN32 AND (NOT ANDROID)) target_link_libraries(${yasio_target_name} pthread) endif() @@ -448,6 +467,7 @@ macro (yasio_config_lib_options target_name) yasio_config_pred(${target_name} YASIO_DISABLE_POLL) yasio_config_pred(${target_name} YASIO_DISABLE_EPOLL) yasio_config_pred(${target_name} YASIO_DISABLE_KQUEUE) + yasio_config_pred(${target_name} YASIO_NT_XHRES_TIMER) yasio_config_target_outdir(${yasio_target_name}) endmacro() @@ -478,7 +498,7 @@ if(YASIO_ENABLE_EXT_HTTP) set (BUILD_SHARED_LIBS FALSE CACHE BOOL "" FORCE) set (BUILD_STATIC_LIBS TRUE CACHE BOOL "" FORCE) endif() - add_subdirectory(thirdparty/llhttp) + add_subdirectory(3rdparty/llhttp) # yasio_http add_subdirectory(extensions/yasio_http) @@ -492,6 +512,7 @@ if(YASIO_BUILD_TESTS) add_subdirectory(tests/icmp) add_subdirectory(tests/mcast) add_subdirectory(tests/speed) + add_subdirectory(tests/mtu) add_subdirectory(tests/issue166) add_subdirectory(tests/issue178) add_subdirectory(tests/issue201) @@ -504,7 +525,7 @@ if(YASIO_BUILD_TESTS) add_subdirectory(tests/echo_client) if(YASIO_ENABLE_LUA AND YASIO_BUILD_LUA_EXAMPLE) add_subdirectory(examples/lua) - target_include_directories(example_lua PRIVATE thirdparty) + target_include_directories(example_lua PRIVATE 3rdparty) target_compile_definitions(example_lua PRIVATE YASIO_LUA_ENABLE_GLOBAL=0) endif() if (NOT YASIO_NO_DEPS) diff --git a/NativeLibs/yasio/build_android.sh b/NativeLibs/yasio/build_android.sh index bd23f69..aea7b96 100755 --- a/NativeLibs/yasio/build_android.sh +++ b/NativeLibs/yasio/build_android.sh @@ -18,7 +18,7 @@ function build() { ABI=$2 TOOLCHAIN_ANME=$3 BUILD_PATH=build.Android.${ABI} - cmake -H. -B${BUILD_PATH} -DANDROID_ABI=${ABI} -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=${NDK}/build/cmake/android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=${API} -DANDROID_TOOLCHAIN=clang -DANDROID_TOOLCHAIN_NAME=${TOOLCHAIN_ANME} + cmake -H. -B${BUILD_PATH} -DANDROID_ABI=${ABI} -DYASIO_BUILD_TESTS=OFF -DBUILD_SHARED_LIBS=ON -DYASIO_NO_DEPS=ON -DYASIO_ENABLE_NI=ON -DYASIO_ENABLE_KCP=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=${NDK}/build/cmake/android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=${API} -DANDROID_TOOLCHAIN=clang -DANDROID_TOOLCHAIN_NAME=${TOOLCHAIN_ANME} cmake --build ${BUILD_PATH} --config Release mkdir -p plugin_android/Plugins/Android/libs/${ABI}/ cp ${BUILD_PATH}/stripped/libyasio.so plugin_android/Plugins/Android/libs/${ABI}/libyasio.so diff --git a/NativeLibs/yasio/build_ios.sh b/NativeLibs/yasio/build_ios.sh index 37da558..fd82926 100755 --- a/NativeLibs/yasio/build_ios.sh +++ b/NativeLibs/yasio/build_ios.sh @@ -1,5 +1,5 @@ mkdir -p build_ios && cd build_ios -cmake -DCMAKE_SYSTEM_NAME=iOS "-DCMAKE_OSX_ARCHITECTURES=arm64" -GXcode ../ +cmake -DCMAKE_SYSTEM_NAME=iOS "-DCMAKE_OSX_ARCHITECTURES=arm64" -GXcode ../ -DYASIO_NO_DEPS=ON -DYASIO_ENABLE_NI=ON -DYASIO_ENABLE_KCP=ON -DYASIO_BUILD_TESTS=OFF cd .. cmake --build build_ios --config Release mkdir -p plugin_ios/Plugins/iOS/ diff --git a/NativeLibs/yasio/build_linux.sh b/NativeLibs/yasio/build_linux.sh index 6219064..5e6a751 100755 --- a/NativeLibs/yasio/build_linux.sh +++ b/NativeLibs/yasio/build_linux.sh @@ -1,4 +1,4 @@ -cmake -B build_linux64 -DBUILD_SHARED_LIBS=ON -DYAISO_ENABLE_NI=ON +cmake -B build_linux64 -DBUILD_SHARED_LIBS=ON -DYASIO_NO_DEPS=ON -DYASIO_ENABLE_NI=ON -DYASIO_ENABLE_KCP=ON -DYASIO_BUILD_TESTS=OFF cmake --build build_linux64 --config Release mkdir -p plugin_linux/Plugins/x86_64 diff --git a/NativeLibs/yasio/build_osx.sh b/NativeLibs/yasio/build_osx.sh index 338fec1..8a2d75c 100755 --- a/NativeLibs/yasio/build_osx.sh +++ b/NativeLibs/yasio/build_osx.sh @@ -1,5 +1,5 @@ mkdir -p build_osx && cd build_osx -cmake -GXcode ../ -DYAISO_ENABLE_NI=ON -DBUILD_SHARED_LIBS=ON +cmake -GXcode ../ -DBUILD_SHARED_LIBS=ON -DYASIO_NO_DEPS=ON -DYASIO_ENABLE_NI=ON -DYASIO_ENABLE_KCP=ON -DYASIO_BUILD_TESTS=OFF cd .. cmake --build build_osx --config Release mkdir -p plugin_osx/Plugins/yasio.bundle/Contents/MacOS/ diff --git a/NativeLibs/yasio/build_uwp.bat b/NativeLibs/yasio/build_uwp.bat index a924fee..4f8484b 100644 --- a/NativeLibs/yasio/build_uwp.bat +++ b/NativeLibs/yasio/build_uwp.bat @@ -1,19 +1,20 @@ -cmake -B build_uwp -A Win32 -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" -DBUILD_SHARED_LIBS=ON -DYAISO_ENABLE_NI=ON +set cmake_options=-DBUILD_SHARED_LIBS=ON -DYASIO_NO_DEPS=ON -DYASIO_ENABLE_NI=ON -DYASIO_ENABLE_KCP=ON -DYASIO_BUILD_TESTS=OFF +cmake -B build_uwp -A Win32 -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" %cmake_options% cmake --build build_uwp --config MinSizeRel md plugin_win\Plugins\WSA\x86 copy /Y build_uwp\MinSizeRel\yasio.dll plugin_win\Plugins\WSA\x86\ -cmake -B build_uwp64 -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" -DBUILD_SHARED_LIBS=ON -DYAISO_ENABLE_NI=ON +cmake -B build_uwp64 -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" %cmake_options% cmake --build build_uwp64 --config MinSizeRel md plugin_win\Plugins\WSA\x64 copy /Y build_uwp64\MinSizeRel\yasio.dll plugin_win\Plugins\WSA\x64\ -cmake -B build_uwp_arm -A ARM -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" -DBUILD_SHARED_LIBS=ON -DYAISO_ENABLE_NI=ON +cmake -B build_uwp_arm -A ARM -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" %cmake_options% cmake --build build_uwp_arm --config MinSizeRel md plugin_win\Plugins\WSA\ARM copy /Y build_uwp_arm\MinSizeRel\yasio.dll plugin_win\Plugins\WSA\ARM\ -cmake -B build_uwp_arm64 -A ARM64 -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" -DBUILD_SHARED_LIBS=ON -DYAISO_ENABLE_NI=ON +cmake -B build_uwp_arm64 -A ARM64 -DCMAKE_SYSTEM_NAME=WindowsStore "-DCMAKE_SYSTEM_VERSION=10.0" %cmake_options% cmake --build build_uwp_arm64 --config MinSizeRel md plugin_win\Plugins\WSA\ARM64 copy /Y build_uwp_arm64\MinSizeRel\yasio.dll plugin_win\Plugins\WSA\ARM64\ diff --git a/NativeLibs/yasio/build_win.bat b/NativeLibs/yasio/build_win.bat index 44f612c..34f57e5 100644 --- a/NativeLibs/yasio/build_win.bat +++ b/NativeLibs/yasio/build_win.bat @@ -1,9 +1,12 @@ -cmake -B build_x64 -A x64 -DBUILD_SHARED_LIBS=ON -DYAISO_ENABLE_NI=ON +set cmake_options=-DBUILD_SHARED_LIBS=ON -DYASIO_NO_DEPS=ON -DYASIO_ENABLE_NI=ON -DYASIO_ENABLE_KCP=ON -DYASIO_BUILD_TESTS=OFF +cmake -B build_x64 -A x64 %cmake_options% cmake --build build_x64 --config MinSizeRel md plugin_win\Plugins\x86_64 copy /y build_x64\MinSizeRel\yasio.dll plugin_win\Plugins\x86_64\ -cmake -B build_x86 -A Win32 -DBUILD_SHARED_LIBS=ON -DYAISO_ENABLE_NI=ON +cmake -B build_x86 -A Win32 %cmake_options% cmake --build build_x86 --config MinSizeRel md plugin_win\Plugins\x86 copy /y build_x86\MinSizeRel\yasio.dll plugin_win\Plugins\x86\ + +if "%GITHUB_ACTIONS%"=="" copy /y plugin_win\Plugins\x86_64\yasio.dll ..\..\Assets\Plugins\x86_64\ diff --git a/NativeLibs/yasio/kcp/LICENSE b/NativeLibs/yasio/kcp/LICENSE deleted file mode 100644 index 4f9f28f..0000000 --- a/NativeLibs/yasio/kcp/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Lin Wei (skywind3000 at gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/NativeLibs/yasio/kcp/README.md b/NativeLibs/yasio/kcp/README.md deleted file mode 100644 index d44e52c..0000000 --- a/NativeLibs/yasio/kcp/README.md +++ /dev/null @@ -1,278 +0,0 @@ -KCP - A Fast and Reliable ARQ Protocol -====================================== - -[![Powered][3]][1] [![Build Status][4]][5] -[![Backers on Open Collective](https://opencollective.com/kcp/backers/badge.svg)](#backers) - [![Sponsors on Open Collective](https://opencollective.com/kcp/sponsors/badge.svg)](#sponsors) - -[1]: https://github.com/skywind3000/kcp -[2]: https://github.com/skywind3000/kcp/raw/master/kcp.svg -[3]: https://github.com/skywind3000/kcp/raw/master/kcp.svg -[4]: https://api.travis-ci.org/skywind3000/kcp.svg?branch=master -[5]: https://travis-ci.org/skywind3000/kcp - -[README in English](https://github.com/skywind3000/kcp/blob/master/README.en.md) - -# 简介 - -KCP是一个快速可靠协议,能以比 TCP 浪费 10%-20% 的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定义下层数据包的发送方式,以 callback的方式提供给 KCP。 连时钟都需要外部传递进来,内部不会有任何一次系统调用。 - -整个协议只有 ikcp.h, ikcp.c两个源文件,可以方便的集成到用户自己的协议栈中。也许你实现了一个P2P,或者某个基于 UDP的协议,而缺乏一套完善的ARQ可靠协议实现,那么简单的拷贝这两个文件到现有项目中,稍微编写两行代码,即可使用。 - - -# 技术特性 - -TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而 KCP是为流速设计的(单个数据包从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比 TCP快30%-40%的传输速度。TCP信道是一条流速很慢,但每秒流量很大的大运河,而KCP是水流湍急的小激流。KCP有正常模式和快速模式两种,通过以下策略达到提高流速的结果: - -#### RTO翻倍vs不翻倍: - - TCP超时计算是RTOx2,这样连续丢三次包就变成RTOx8了,十分恐怖,而KCP启动快速模式后不x2,只是x1.5(实验证明1.5这个值相对比较好),提高了传输速度。 - -#### 选择性重传 vs 全部重传: - - TCP丢包时会全部重传从丢的那个包开始以后的数据,KCP是选择性重传,只重传真正丢失的数据包。 - -#### 快速重传: - - 发送端发送了1,2,3,4,5几个包,然后收到远端的ACK: 1, 3, 4, 5,当收到ACK3时,KCP知道2被跳过1次,收到ACK4时,知道2被跳过了2次,此时可以认为2号丢失,不用等超时,直接重传2号包,大大改善了丢包时的传输速度。 - -#### 延迟ACK vs 非延迟ACK: - - TCP为了充分利用带宽,延迟发送ACK(NODELAY都没用),这样超时计算会算出较大 RTT时间,延长了丢包时的判断过程。KCP的ACK是否延迟发送可以调节。 - -#### UNA vs ACK+UNA: - - ARQ模型响应有两种,UNA(此编号前所有包已收到,如TCP)和ACK(该编号包已收到),光用UNA将导致全部重传,光用ACK则丢失成本太高,以往协议都是二选其一,而 KCP协议中,除去单独的 ACK包外,所有包都有UNA信息。 - -#### 非退让流控: - - KCP正常模式同TCP一样使用公平退让法则,即发送窗口大小由:发送缓存大小、接收端剩余接收缓存大小、丢包退让及慢启动这四要素决定。但传送及时性要求很高的小数据时,可选择通过配置跳过后两步,仅用前两项来控制发送频率。以牺牲部分公平性及带宽利用率之代价,换取了开着BT都能流畅传输的效果。 - - -# 快速安装 - -您可以使用[vcpkg](https://github.com/Microsoft/vcpkg)库管理器下载并安装kcp: - - git clone https://github.com/Microsoft/vcpkg.git - cd vcpkg - ./bootstrap-vcpkg.sh - ./vcpkg integrate install - ./vcpkg install kcp - -vcpkg中的kcp库由Microsoft团队成员和社区贡献者保持最新状态。如果版本过时,请在vcpkg存储库上[创建issue或提出PR](https://github.com/Microsoft/vcpkg)。 - -# 基本使用 - -1. 创建 KCP对象: - - ```cpp - // 初始化 kcp对象,conv为一个表示会话编号的整数,和tcp的 conv一样,通信双 - // 方需保证 conv相同,相互的数据包才能够被认可,user是一个给回调函数的指针 - ikcpcb *kcp = ikcp_create(conv, user); - ``` - -2. 设置回调函数: - - ```cpp - // KCP的下层协议输出函数,KCP需要发送数据时会调用它 - // buf/len 表示缓存和长度 - // user指针为 kcp对象创建时传入的值,用于区别多个 KCP对象 - int udp_output(const char *buf, int len, ikcpcb *kcp, void *user) - { - .... - } - // 设置回调函数 - kcp->output = udp_output; - ``` - -3. 循环调用 update: - - ```cpp - // 以一定频率调用 ikcp_update来更新 kcp状态,并且传入当前时钟(毫秒单位) - // 如 10ms调用一次,或用 ikcp_check确定下次调用 update的时间不必每次调用 - ikcp_update(kcp, millisec); - ``` - -4. 输入一个下层数据包: - - ```cpp - // 收到一个下层数据包(比如UDP包)时需要调用: - ikcp_input(kcp, received_udp_packet, received_udp_size); - ``` - 处理了下层协议的输出/输入后 KCP协议就可以正常工作了,使用 ikcp_send 来向 - 远端发送数据。而另一端使用 ikcp_recv(kcp, ptr, size)来接收数据。 - - -# 协议配置 - -协议默认模式是一个标准的 ARQ,需要通过配置打开各项加速开关: - -1. 工作模式: - ```cpp - int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc) - ``` - - - nodelay :是否启用 nodelay模式,0不启用;1启用。 - - interval :协议内部工作的 interval,单位毫秒,比如 10ms或者 20ms - - resend :快速重传模式,默认0关闭,可以设置2(2次ACK跨越将会直接重传) - - nc :是否关闭流控,默认是0代表不关闭,1代表关闭。 - - 普通模式: ikcp_nodelay(kcp, 0, 40, 0, 0); - - 极速模式: ikcp_nodelay(kcp, 1, 10, 2, 1); - -2. 最大窗口: - ```cpp - int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd); - ``` - 该调用将会设置协议的最大发送窗口和最大接收窗口大小,默认为32. 这个可以理解为 TCP的 SND_BUF 和 RCV_BUF,只不过单位不一样 SND/RCV_BUF 单位是字节,这个单位是包。 - -3. 最大传输单元: - - 纯算法协议并不负责探测 MTU,默认 mtu是1400字节,可以使用ikcp_setmtu来设置该值。该值将会影响数据包归并及分片时候的最大传输单元。 - -4. 最小RTO: - - 不管是 TCP还是 KCP计算 RTO时都有最小 RTO的限制,即便计算出来RTO为40ms,由于默认的 RTO是100ms,协议只有在100ms后才能检测到丢包,快速模式下为30ms,可以手动更改该值: - ```cpp - kcp->rx_minrto = 10; - ``` - - -# 文档索引 - -协议的使用和配置都是很简单的,大部分情况看完上面的内容基本可以使用了。如果你需要进一步进行精细的控制,比如改变 KCP的内存分配器,或者你需要更有效的大规模调度 KCP链接(比如 3500个以上),或者如何更好的同 TCP结合,那么可以继续延伸阅读: - -- [Wiki Home](https://github.com/skywind3000/kcp/wiki) -- [KCP 最佳实践](https://github.com/skywind3000/kcp/wiki/KCP-Best-Practice) -- [同现有TCP服务器集成](https://github.com/skywind3000/kcp/wiki/Cooperate-With-Tcp-Server) -- [传输数据加密](https://github.com/skywind3000/kcp/wiki/Network-Encryption) -- [应用层流量控制](https://github.com/skywind3000/kcp/wiki/Flow-Control-for-Users) -- [性能评测](https://github.com/skywind3000/kcp/wiki/KCP-Benchmark) - - -# 开源案例 - -- [kcptun](https://github.com/xtaci/kcptun): 基于 kcp-go做的高速远程端口转发(隧道) ,配合ssh -D,可以比 shadowsocks 更流畅的看在线视频。 -- [dog-tunnel](https://github.com/vzex/dog-tunnel): GO开发的网络隧道,使用 KCP极大的改进了传输速度,并移植了一份 GO版本 KCP -- [v2ray](https://www.v2ray.com): 著名代理软件,Shadowsocks 代替者,1.17后集成了 kcp协议,使用UDP传输,无数据包特征。 -- [HP-Socket](https://github.com/ldcsaa/HP-Socket): 高性能网络通信框架 HP-Socket。 -- [frp](https://github.com/fatedier/frp): 高性能内网穿透的反向代理软件,可将将内网服务暴露映射到外网服务器。 -- [asio-kcp](https://github.com/libinzhangyuan/asio_kcp): 使用 KCP的完整 UDP网络库,完整实现了基于 UDP的链接状态管理,会话控制,KCP协议调度等 -- [kcp-java](https://github.com/hkspirt/kcp-java): Java版本 KCP协议实现。 -- [kcp-netty](https://github.com/szhnet/kcp-netty): kcp的Java语言实现,基于netty。 -- [java-kcp](https://github.com/l42111996/java-Kcp): JAVA版本KCP,基于netty实现(包含fec功能) -- [csharp-kcp](https://github.com/l42111996/csharp-kcp): csharp版本KCP,基于dotNetty实现(包含fec功能) -- [kcp-cpp](https://github.com/Unit-X/kcp-cpp): KCP 的多平台(Windows、MacOS、Linux)C++ 实现作为应用程序中的简单库。包含适用于所有平台的套接字处理和辅助函数。 -- [kcp-perl](https://github.com/Homqyy/kcp-perl): kcp的Perl实现,其是面向对象的,Perl-Like的。 -- [kcp-go](https://github.com/xtaci/kcp-go): 高安全性的kcp的 GO语言实现,包含 UDP会话管理的简单实现,可以作为后续开发的基础库。 -- [kcp-csharp](https://github.com/limpo1989/kcp-csharp): kcp的 csharp移植,同时包含一份回话管理,可以连接上面kcp-go的服务端。 -- [kcp-csharp](https://github.com/KumoKyaku/KCP): 新版本 Kcp的 csharp移植。线程安全,运行时无alloc,对gc无压力。 -- [kcp2k](https://github.com/vis2k/kcp2k/): Line-by-line translation to C#, with optional Server/Client on top. -- [kcp-rs](https://github.com/en/kcp-rs): KCP的 rust移植 -- [kcp-rust](https://github.com/Matrix-Zhang/kcp):新版本 KCP的 rust 移植 -- [tokio-kcp](https://github.com/Matrix-Zhang/tokio_kcp):rust tokio 的 kcp 集成 -- [kcp-rust-native](https://github.com/b23r0/kcp-rust-native):rust 的 kcp bindings -- [lua-kcp](https://github.com/linxiaolong/lua-kcp): KCP的 Lua扩展,用于 Lua服务器 -- [node-kcp](https://github.com/leenjewel/node-kcp): node-js 的 KCP 接口 -- [nysocks](https://github.com/oyyd/nysocks): 基于libuv实现的[node-addon](https://nodejs.org/api/addons.html),提供nodejs版本的代理服务,客户端接入支持SOCKS5和ss两种协议 -- [shadowsocks-android](https://github.com/shadowsocks/shadowsocks-android): Shadowsocks for android 集成了 kcptun 使用 kcp协议加速 shadowsocks,效果不错 -- [kcpuv](https://github.com/elisaday/kcpuv): 使用 libuv开发的kcpuv库,目前还在 Demo阶段 -- [Lantern](https://getlantern.org/):更好的 VPN,Github 50000 星,使用 kcpgo 加速 -- [rpcx](https://github.com/smallnest/rpcx) :RPC 框架,1000+ 星,使用 kcpgo 加速 RPC -- [xkcptun](https://github.com/liudf0716/xkcptun): c语言实现的kcptun,主要用于[OpenWrt](https://github.com/openwrt/openwrt), [LEDE](https://github.com/lede-project/source)开发的路由器项目上 -- [et-frame](https://github.com/egametang/ET): C#前后端框架(前端unity3d),统一用C#开发游戏,实现了前后端kcp协议 -- [yasio](https://github.com/yasio/yasio): 一个跨平台专注于任意客户端程序的异步socket库, 易于使用,相同的API操作KCP/TCP/UDP, 性能测试结果: [benchmark-pump](https://github.com/yasio/yasio/blob/master/benchmark.md). -- [gouxp](https://github.com/shaoyuan1943/gouxp): 用Go实现基于回调方式的KCP开发包,包含加解密和FEC支持,简单易用。 -- [skcp](https://github.com/xboss/skcp): 基于libev实现的库,具备传输加密及基本的连接管理能力。 -- [pykcp](https://github.com/enkiller/pykcp): Python 版本的 KCP 实现 - -# 商业案例 - -- [原神](https://ys.mihoyo.com/):米哈游的《原神》使用 KCP 降低游戏消息的传输耗时,提升操作的体验。 -- [SpatialOS](https://improbable.io/spatialOS): 大型多人分布式游戏服务端引擎,BigWorld 的后继者,使用 KCP 加速数据传输。 -- [西山居](https://www.xishanju.com/):使用 KCP 进行游戏数据加速。 -- [CC](http://cc.163.com/):网易 CC 使用 kcp 加速视频推流,有效提高流畅性 -- [BOBO](http://bobo.163.com/):网易 BOBO 使用 kcp 加速主播推流 -- [UU](https://uu.163.com):网易 UU 加速器使用 KCP/KCPTUN 经行远程传输加速。 -- [阿里云](https://cn.aliyun.com/):阿里云的视频传输加速服务 GRTN 使用 KCP 进行音视频数据传输优化,动态加速产品也使用 KCP。 -- [云帆加速](http://www.yfcloud.com/):使用 KCP 加速文件传输和视频推流,优化了台湾主播推流的流畅度。 -- [明日帝国](https://www.taptap.com/app/50664):Game K17 的 《明日帝国》 (Google Play),使用 KCP 加速游戏消息,让全球玩家流畅联网 -- [仙灵大作战](https://www.taptap.com/app/27242):4399 的 MOBA游戏,使用 KCP 优化游戏同步 - -KCP 成功的运行在多个用户规模上亿的项目上,为他们提供了更加灵敏和丝滑网络体验。 - -欢迎告知更多案例 - -# 协议比较 - -如果网络永远不卡,那 KCP/TCP 表现类似,但是网络本身就是不可靠的,丢包和抖动无法避免(否则还要各种可靠协议干嘛)。在内网这种几乎理想的环境里直接比较,大家都差不多,但是放到公网上,放到3G/4G网络情况下,或者使用内网丢包模拟,差距就很明显了。公网在高峰期有平均接近10%的丢包,wifi/3g/4g下更糟糕,这些都会让传输变卡。 - -感谢 [asio-kcp](https://github.com/libinzhangyuan/asio_kcp) 的作者 [zhangyuan](https://github.com/libinzhangyuan) 对 KCP 与 enet, udt做过的一次横向评测,结论如下: - -- ASIO-KCP **has good performace in wifi and phone network(3G, 4G)**. -- The kcp is the **first choice for realtime pvp game**. -- The lag is less than 1 second when network lag happen. **3 times better than enet** when lag happen. -- The enet is a good choice if your game allow 2 second lag. -- **UDT is a bad idea**. It always sink into badly situation of more than serval seconds lag. And the recovery is not expected. -- enet has the problem of lack of doc. And it has lots of functions that you may intrest. -- kcp's doc is chinese. Good thing is the function detail which is writen in code is english. And you can use asio_kcp which is a good wrap. -- The kcp is a simple thing. You will write more code if you want more feature. -- UDT has a perfect doc. UDT may has more bug than others as I feeling. - -具体见:[横向比较](https://github.com/libinzhangyuan/reliable_udp_bench_mark) 和 [评测数据](https://github.com/skywind3000/kcp/wiki/KCP-Benchmark),为犹豫选择的人提供了更多指引。 - -大型多人游戏服务端引擎 [SpatialOS](https://improbable.io/spatialOS) 在集成 KCP 协议后做了同 TCP/RakNet 的评测: - -![](https://github.com/skywind3000/kcp/raw/master/images/spatialos-50.png) - -对比了在服务端刷新率为 60 Hz 同时维护 50 个角色时的响应时间,详细对比报告见: - -- [Kcp a new low latency secure network stack](https://improbable.io/blog/kcp-a-new-low-latency-secure-network-stack) - - -# 关于协议 - -近年来,网络游戏和各类社交网络都在成几何倍数的增长,不管网络游戏还是各类互动社交网络,交互性和复杂度都在迅速提高,都需要在极短的时间内将数据同时投递给大量用户,因此传输技术自然变为未来制约发展的一个重要因素,而开源界里各种著名的传输协议,如 raknet/enet 之类,一发布都是整套协议栈一起发布,这种形式是不利于多样化的,我的项目只能选择用或者不用你,很难选择 “部分用你”,然而你一套协议栈设计的再好,是非常难以满足不同角度的各种需求的。 - -因此 KCP 的方式是把协议栈 “拆开”,让大家可以根据项目需求进行灵活的调整和组装,你可以下面加一层 reed solomon 的纠删码做 FEC,上面加一层类 RC4/Salsa20 做流加密,握手处再设计一套非对称密钥交换,底层 UDP 传输层再做一套动态路由系统,同时探测多条路径,选最好路径进行传输。这些不同的 “协议单元” 可以像搭建积木一般根据需要自由组合,保证 “简单性” 和 “可拆分性”,这样才能灵活适配多变的业务需求,哪个模块不好,换了就是。 - -未来传输方面的解决方案必然是根据使用场景深度定制的,因此给大家一个可以自由组合的 “协议单元” ,方便大家集成在自己的协议栈中。 - -For more information, please see the [Success Stories](https://github.com/skywind3000/kcp/wiki/Success-Stories). - - -# 关于作者 - -作者:林伟 (skywind3000) - -欢迎关注我的:[twitter](https://twitter.com/skywind3000) 和 [zhihu](https://www.zhihu.com/people/skywind3000)。 - -我在多年的开发经历中,一直都喜欢研究解决程序中的一些瓶颈问题,早年喜欢游戏开发,照着《VGA编程》来做游戏图形,读 Michael Abrash 的《图形程序开发人员指南》做软渲染器,爱好摆弄一些能够榨干 CPU 能够运行更快的代码,参加工作后,兴趣转移到服务端和网络相关的技术。 - -2007 年时做了几个传统游戏后开始研究快速动作游戏的同步问题,期间写过不少文章,算是国内比较早研究同步问题的人,然而发现不管怎么解决同步都需要在网络传输方面有所突破,后来离开游戏转行互联网后也发现不少领域有这方面的需求,于是开始花时间在网络传输这个领域上,尝试基于 UDP 实现一些保守的可靠协议,仿照 BSD Lite 4.4 的代码实现一些类 TCP 协议,觉得比较有意思,又接着实现一些 P2P 和动态路由网相关的玩具。KCP 协议诞生于 2011 年,基本算是自己传输方面做的几个玩具中的一个。 - -Kcptun 的作者 xtaci 是我的大学同学,我俩都是学通信的,经常在一起研究如何进行传输优化。 - -# 欢迎捐赠 - -![欢迎使用支付宝对该项目进行捐赠](images/donation.png) - -欢迎使用支付宝手扫描上面的二维码,对该项目进行捐赠。捐赠款项将用于持续优化 KCP协议以及完善文档。 - -感谢:明明、星仔、进、帆、颁钊、斌铨、晓丹、余争、虎、晟敢、徐玮、王川、赵刚强、胡知锋、万新朝、何新超、刘旸、侯宪辉、吴佩仪、华斌、如涛、胡坚。。。(早先的名单实在不好意思没记录下来)等同学的捐助与支持。 - - -欢迎关注 - -KCP交流群:364933586(QQ群号),KCP集成,调优,网络传输以及相关技术讨论 - -Gitter 群:https://gitter.im/skywind3000/KCP - -blog: http://www.skywind.me - - - -## Contributors - -This project exists thanks to all the people who contribute. - - diff --git a/NativeLibs/yasio/manifest.json b/NativeLibs/yasio/manifest.json new file mode 100644 index 0000000..9ed3a2a --- /dev/null +++ b/NativeLibs/yasio/manifest.json @@ -0,0 +1,14 @@ +{ + "versions": { + "1kdist": "72" + }, + "mirrors": { + "github": { + "1kdist": "simdsoft/1kiss/releases/download" + }, + "gitee": + { + "1kdist": "simdsoft/1kiss/releases/download" + } + } +} diff --git a/NativeLibs/yasio/yasio/bindings/lyasio.cpp b/NativeLibs/yasio/yasio/bindings/lyasio.cpp index 1866220..53fc916 100644 --- a/NativeLibs/yasio/yasio/bindings/lyasio.cpp +++ b/NativeLibs/yasio/yasio/bindings/lyasio.cpp @@ -4,7 +4,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -259,13 +259,13 @@ YASIO_LUA_API int luaopen_yasio(lua_State* L) "write", sol::overload( [](io_service* service, transport_handle_t transport, cxx17::string_view s) { - return service->write(transport, yasio::sbyte_buffer{s.data(), s.data() + s.length(), std::true_type{}}); + return service->write(transport, yasio::sbyte_buffer{s.data(), s.data() + s.length()}); }, [](io_service* service, transport_handle_t transport, yasio::obstream* obs) { return service->write(transport, std::move(obs->buffer())); }), "write_to", sol::overload( [](io_service* service, transport_handle_t transport, cxx17::string_view s, cxx17::string_view ip, u_short port) { - return service->write_to(transport, yasio::sbyte_buffer{s.data(), s.data() + s.length(), std::true_type{}}, ip::endpoint{ip.data(), port}); + return service->write_to(transport, yasio::sbyte_buffer{s.data(), s.data() + s.length()}, ip::endpoint{ip.data(), port}); }, [](io_service* service, transport_handle_t transport, yasio::obstream* obs, cxx17::string_view ip, u_short port) { return service->write_to(transport, std::move(obs->buffer()), ip::endpoint{ip.data(), port}); @@ -298,63 +298,67 @@ YASIO_LUA_API int luaopen_yasio(lua_State* L) }; // ##-- yasio enums -# define YASIO_EXPORT_ENUM(v) yasio_lib[#v] = v - YASIO_EXPORT_ENUM(YCK_TCP_CLIENT); - YASIO_EXPORT_ENUM(YCK_TCP_SERVER); - YASIO_EXPORT_ENUM(YCK_UDP_CLIENT); - YASIO_EXPORT_ENUM(YCK_UDP_SERVER); +# define YASIO_EXPORT_ANY(v) yasio_lib[#v] = v + YASIO_EXPORT_ANY(YCK_TCP_CLIENT); + YASIO_EXPORT_ANY(YCK_TCP_SERVER); + YASIO_EXPORT_ANY(YCK_UDP_CLIENT); + YASIO_EXPORT_ANY(YCK_UDP_SERVER); # if defined(YASIO_ENABLE_KCP) - YASIO_EXPORT_ENUM(YCK_KCP_CLIENT); - YASIO_EXPORT_ENUM(YCK_KCP_SERVER); + YASIO_EXPORT_ANY(YCK_KCP_CLIENT); + YASIO_EXPORT_ANY(YCK_KCP_SERVER); # endif # if defined(YASIO_SSL_BACKEND) - YASIO_EXPORT_ENUM(YCK_SSL_CLIENT); + YASIO_EXPORT_ANY(YCK_SSL_CLIENT); # endif - YASIO_EXPORT_ENUM(YOPT_S_CONNECT_TIMEOUT); - YASIO_EXPORT_ENUM(YOPT_S_DNS_CACHE_TIMEOUT); - YASIO_EXPORT_ENUM(YOPT_S_DNS_QUERIES_TIMEOUT); - YASIO_EXPORT_ENUM(YOPT_S_TCP_KEEPALIVE); - YASIO_EXPORT_ENUM(YOPT_S_EVENT_CB); - YASIO_EXPORT_ENUM(YOPT_C_UNPACK_PARAMS); - YASIO_EXPORT_ENUM(YOPT_C_UNPACK_STRIP); - YASIO_EXPORT_ENUM(YOPT_C_UNPACK_NO_BSWAP); - YASIO_EXPORT_ENUM(YOPT_C_LFBFD_PARAMS); // alias for YOPT_C_UNPACK_PARAMS - YASIO_EXPORT_ENUM(YOPT_C_LOCAL_HOST); - YASIO_EXPORT_ENUM(YOPT_C_LOCAL_PORT); - YASIO_EXPORT_ENUM(YOPT_C_LOCAL_ENDPOINT); - YASIO_EXPORT_ENUM(YOPT_C_REMOTE_HOST); - YASIO_EXPORT_ENUM(YOPT_C_REMOTE_PORT); - YASIO_EXPORT_ENUM(YOPT_C_REMOTE_ENDPOINT); - YASIO_EXPORT_ENUM(YOPT_C_ENABLE_MCAST); - YASIO_EXPORT_ENUM(YOPT_C_DISABLE_MCAST); + YASIO_EXPORT_ANY(YOPT_S_CONNECT_TIMEOUT); + YASIO_EXPORT_ANY(YOPT_S_DNS_CACHE_TIMEOUT); + YASIO_EXPORT_ANY(YOPT_S_DNS_QUERIES_TIMEOUT); + YASIO_EXPORT_ANY(YOPT_S_TCP_KEEPALIVE); + YASIO_EXPORT_ANY(YOPT_S_EVENT_CB); + YASIO_EXPORT_ANY(YOPT_C_UNPACK_PARAMS); + YASIO_EXPORT_ANY(YOPT_C_UNPACK_STRIP); + YASIO_EXPORT_ANY(YOPT_C_UNPACK_NO_BSWAP); + YASIO_EXPORT_ANY(YOPT_C_LFBFD_PARAMS); // alias for YOPT_C_UNPACK_PARAMS + YASIO_EXPORT_ANY(YOPT_C_LOCAL_HOST); + YASIO_EXPORT_ANY(YOPT_C_LOCAL_PORT); + YASIO_EXPORT_ANY(YOPT_C_LOCAL_ENDPOINT); + YASIO_EXPORT_ANY(YOPT_C_REMOTE_HOST); + YASIO_EXPORT_ANY(YOPT_C_REMOTE_PORT); + YASIO_EXPORT_ANY(YOPT_C_REMOTE_ENDPOINT); + YASIO_EXPORT_ANY(YOPT_C_ENABLE_MCAST); + YASIO_EXPORT_ANY(YOPT_C_DISABLE_MCAST); # if defined(YASIO_ENABLE_KCP) - YASIO_EXPORT_ENUM(YOPT_C_KCP_CONV); - YASIO_EXPORT_ENUM(YOPT_C_KCP_NODELAY); - YASIO_EXPORT_ENUM(YOPT_C_KCP_WINDOW_SIZE); - YASIO_EXPORT_ENUM(YOPT_C_KCP_MTU); - YASIO_EXPORT_ENUM(YOPT_C_KCP_RTO_MIN); + YASIO_EXPORT_ANY(YOPT_C_KCP_CONV); + YASIO_EXPORT_ANY(YOPT_C_KCP_NODELAY); + YASIO_EXPORT_ANY(YOPT_C_KCP_WINDOW_SIZE); + YASIO_EXPORT_ANY(YOPT_C_KCP_MTU); + YASIO_EXPORT_ANY(YOPT_C_KCP_RTO_MIN); # endif - YASIO_EXPORT_ENUM(YOPT_C_MOD_FLAGS); + YASIO_EXPORT_ANY(YOPT_C_MOD_FLAGS); - YASIO_EXPORT_ENUM(YCF_REUSEADDR); - YASIO_EXPORT_ENUM(YCF_EXCLUSIVEADDRUSE); + YASIO_EXPORT_ANY(YCF_REUSEADDR); + YASIO_EXPORT_ANY(YCF_EXCLUSIVEADDRUSE); - YASIO_EXPORT_ENUM(YEK_ON_OPEN); - YASIO_EXPORT_ENUM(YEK_ON_CLOSE); - YASIO_EXPORT_ENUM(YEK_ON_PACKET); - YASIO_EXPORT_ENUM(YEK_CONNECT_RESPONSE); - YASIO_EXPORT_ENUM(YEK_CONNECTION_LOST); - YASIO_EXPORT_ENUM(YEK_PACKET); + YASIO_EXPORT_ANY(YEK_ON_OPEN); + YASIO_EXPORT_ANY(YEK_ON_CLOSE); + YASIO_EXPORT_ANY(YEK_ON_PACKET); + YASIO_EXPORT_ANY(YEK_CONNECT_RESPONSE); + YASIO_EXPORT_ANY(YEK_CONNECTION_LOST); + YASIO_EXPORT_ANY(YEK_PACKET); - YASIO_EXPORT_ENUM(SEEK_CUR); - YASIO_EXPORT_ENUM(SEEK_SET); - YASIO_EXPORT_ENUM(SEEK_END); + YASIO_EXPORT_ANY(SEEK_CUR); + YASIO_EXPORT_ANY(SEEK_SET); + YASIO_EXPORT_ANY(SEEK_END); using namespace lyasio; - YASIO_EXPORT_ENUM(BUFFER_DEFAULT); - YASIO_EXPORT_ENUM(BUFFER_RAW); - YASIO_EXPORT_ENUM(BUFFER_FAST); + YASIO_EXPORT_ANY(BUFFER_DEFAULT); + YASIO_EXPORT_ANY(BUFFER_RAW); + YASIO_EXPORT_ANY(BUFFER_FAST); + + char version[32]; + snprintf(version, sizeof(version), "%x.%x.%x", (YASIO_VERSION_NUM >> 16) & 0xff, (YASIO_VERSION_NUM >> 8) & 0xff, YASIO_VERSION_NUM & 0xff); + YASIO_EXPORT_ANY(version); return yasio_lib.push(); /* return 'yasio' table */ } @@ -399,7 +403,7 @@ struct lua_type_traits { { size_t size = 0; const char* buffer = lua_tolstring(l, index, &size); - return yasio::sbyte_buffer(buffer, buffer + size, std::true_type{}); + return yasio::sbyte_buffer(buffer, buffer + size); } static int push(lua_State* l, push_type s) { @@ -737,57 +741,61 @@ end }); // ##-- yasio enums -# define YASIO_EXPORT_ENUM(v) yasio_lib[#v] = v - YASIO_EXPORT_ENUM(YCK_TCP_CLIENT); - YASIO_EXPORT_ENUM(YCK_TCP_SERVER); - YASIO_EXPORT_ENUM(YCK_UDP_CLIENT); - YASIO_EXPORT_ENUM(YCK_UDP_SERVER); +# define YASIO_EXPORT_ANY(v) yasio_lib[#v] = v + YASIO_EXPORT_ANY(YCK_TCP_CLIENT); + YASIO_EXPORT_ANY(YCK_TCP_SERVER); + YASIO_EXPORT_ANY(YCK_UDP_CLIENT); + YASIO_EXPORT_ANY(YCK_UDP_SERVER); # if defined(YASIO_ENABLE_KCP) - YASIO_EXPORT_ENUM(YCK_KCP_CLIENT); - YASIO_EXPORT_ENUM(YCK_KCP_SERVER); + YASIO_EXPORT_ANY(YCK_KCP_CLIENT); + YASIO_EXPORT_ANY(YCK_KCP_SERVER); # endif # if YASIO_SSL_BACKEND - YASIO_EXPORT_ENUM(YCK_SSL_CLIENT); + YASIO_EXPORT_ANY(YCK_SSL_CLIENT); # endif - YASIO_EXPORT_ENUM(YOPT_S_CONNECT_TIMEOUT); - YASIO_EXPORT_ENUM(YOPT_S_DNS_CACHE_TIMEOUT); - YASIO_EXPORT_ENUM(YOPT_S_DNS_QUERIES_TIMEOUT); - YASIO_EXPORT_ENUM(YOPT_S_TCP_KEEPALIVE); - YASIO_EXPORT_ENUM(YOPT_S_EVENT_CB); - YASIO_EXPORT_ENUM(YOPT_C_UNPACK_PARAMS); - YASIO_EXPORT_ENUM(YOPT_C_UNPACK_STRIP); - YASIO_EXPORT_ENUM(YOPT_C_UNPACK_NO_BSWAP); - YASIO_EXPORT_ENUM(YOPT_C_LFBFD_PARAMS); // alias for YOPT_C_UNPACK_PARAMS - YASIO_EXPORT_ENUM(YOPT_C_LOCAL_HOST); - YASIO_EXPORT_ENUM(YOPT_C_LOCAL_PORT); - YASIO_EXPORT_ENUM(YOPT_C_LOCAL_ENDPOINT); - YASIO_EXPORT_ENUM(YOPT_C_REMOTE_HOST); - YASIO_EXPORT_ENUM(YOPT_C_REMOTE_PORT); - YASIO_EXPORT_ENUM(YOPT_C_REMOTE_ENDPOINT); - YASIO_EXPORT_ENUM(YOPT_C_ENABLE_MCAST); - YASIO_EXPORT_ENUM(YOPT_C_DISABLE_MCAST); - YASIO_EXPORT_ENUM(YOPT_C_KCP_CONV); - YASIO_EXPORT_ENUM(YOPT_C_MOD_FLAGS); - - YASIO_EXPORT_ENUM(YCF_REUSEADDR); - YASIO_EXPORT_ENUM(YCF_EXCLUSIVEADDRUSE); - - YASIO_EXPORT_ENUM(YEK_ON_OPEN); - YASIO_EXPORT_ENUM(YEK_ON_CLOSE); - YASIO_EXPORT_ENUM(YEK_ON_PACKET); - YASIO_EXPORT_ENUM(YEK_CONNECT_RESPONSE); - YASIO_EXPORT_ENUM(YEK_CONNECTION_LOST); - YASIO_EXPORT_ENUM(YEK_PACKET); - - YASIO_EXPORT_ENUM(SEEK_CUR); - YASIO_EXPORT_ENUM(SEEK_SET); - YASIO_EXPORT_ENUM(SEEK_END); + YASIO_EXPORT_ANY(YOPT_S_CONNECT_TIMEOUT); + YASIO_EXPORT_ANY(YOPT_S_DNS_CACHE_TIMEOUT); + YASIO_EXPORT_ANY(YOPT_S_DNS_QUERIES_TIMEOUT); + YASIO_EXPORT_ANY(YOPT_S_TCP_KEEPALIVE); + YASIO_EXPORT_ANY(YOPT_S_EVENT_CB); + YASIO_EXPORT_ANY(YOPT_C_UNPACK_PARAMS); + YASIO_EXPORT_ANY(YOPT_C_UNPACK_STRIP); + YASIO_EXPORT_ANY(YOPT_C_UNPACK_NO_BSWAP); + YASIO_EXPORT_ANY(YOPT_C_LFBFD_PARAMS); // alias for YOPT_C_UNPACK_PARAMS + YASIO_EXPORT_ANY(YOPT_C_LOCAL_HOST); + YASIO_EXPORT_ANY(YOPT_C_LOCAL_PORT); + YASIO_EXPORT_ANY(YOPT_C_LOCAL_ENDPOINT); + YASIO_EXPORT_ANY(YOPT_C_REMOTE_HOST); + YASIO_EXPORT_ANY(YOPT_C_REMOTE_PORT); + YASIO_EXPORT_ANY(YOPT_C_REMOTE_ENDPOINT); + YASIO_EXPORT_ANY(YOPT_C_ENABLE_MCAST); + YASIO_EXPORT_ANY(YOPT_C_DISABLE_MCAST); + YASIO_EXPORT_ANY(YOPT_C_KCP_CONV); + YASIO_EXPORT_ANY(YOPT_C_MOD_FLAGS); + + YASIO_EXPORT_ANY(YCF_REUSEADDR); + YASIO_EXPORT_ANY(YCF_EXCLUSIVEADDRUSE); + + YASIO_EXPORT_ANY(YEK_ON_OPEN); + YASIO_EXPORT_ANY(YEK_ON_CLOSE); + YASIO_EXPORT_ANY(YEK_ON_PACKET); + YASIO_EXPORT_ANY(YEK_CONNECT_RESPONSE); + YASIO_EXPORT_ANY(YEK_CONNECTION_LOST); + YASIO_EXPORT_ANY(YEK_PACKET); + + YASIO_EXPORT_ANY(SEEK_CUR); + YASIO_EXPORT_ANY(SEEK_SET); + YASIO_EXPORT_ANY(SEEK_END); using namespace lyasio; - YASIO_EXPORT_ENUM(BUFFER_DEFAULT); - YASIO_EXPORT_ENUM(BUFFER_RAW); - YASIO_EXPORT_ENUM(BUFFER_FAST); + YASIO_EXPORT_ANY(BUFFER_DEFAULT); + YASIO_EXPORT_ANY(BUFFER_RAW); + YASIO_EXPORT_ANY(BUFFER_FAST); + + char version[32]; + snprintf(version, sizeof(version), "%x.%x.%x", (YASIO_VERSION_NUM >> 16) & 0xff, (YASIO_VERSION_NUM >> 8) & 0xff, YASIO_VERSION_NUM & 0xff); + YASIO_EXPORT_ANY(version); return yasio_lib.push(); /* return 'yasio' table */ } diff --git a/NativeLibs/yasio/yasio/bindings/lyasio.hpp b/NativeLibs/yasio/yasio/bindings/lyasio.hpp index 3bb4d7f..481bf78 100644 --- a/NativeLibs/yasio/yasio/bindings/lyasio.hpp +++ b/NativeLibs/yasio/yasio/bindings/lyasio.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/bindings/yasio_axlua.cpp b/NativeLibs/yasio/yasio/bindings/yasio_axlua.cpp index a4c3996..00ba10a 100644 --- a/NativeLibs/yasio/yasio/bindings/yasio_axlua.cpp +++ b/NativeLibs/yasio/yasio/bindings/yasio_axlua.cpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "sol/sol.hpp" #include "yasio/bindings/yasio_axlua.hpp" #include "yasio/bindings/lyasio.hpp" #include "yasio/object_pool.hpp" @@ -118,12 +120,6 @@ YASIO_LUA_API void clear() #if YASIO__HAS_CXX14 -# if YASIO__HAS_CXX17 -# include "sol/sol.hpp" -# else -# include "sol2/sol.hpp" -# endif - extern "C" { struct lua_State; YASIO_LUA_API int luaopen_yasio_axlua(lua_State* L) diff --git a/NativeLibs/yasio/yasio/bindings/yasio_axlua.hpp b/NativeLibs/yasio/yasio/bindings/yasio_axlua.hpp index c60735f..45854fa 100644 --- a/NativeLibs/yasio/yasio/bindings/yasio_axlua.hpp +++ b/NativeLibs/yasio/yasio/bindings/yasio_axlua.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/bindings/yasio_jsb.cpp b/NativeLibs/yasio/yasio/bindings/yasio_jsb.cpp index 2aa60b6..1a7f24d 100644 --- a/NativeLibs/yasio/yasio/bindings/yasio_jsb.cpp +++ b/NativeLibs/yasio/yasio/bindings/yasio_jsb.cpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/bindings/yasio_jsb.hpp b/NativeLibs/yasio/yasio/bindings/yasio_jsb.hpp index a775e20..56c00fc 100644 --- a/NativeLibs/yasio/yasio/bindings/yasio_jsb.hpp +++ b/NativeLibs/yasio/yasio/bindings/yasio_jsb.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/bindings/yasio_jsb20.cpp b/NativeLibs/yasio/yasio/bindings/yasio_jsb20.cpp index 9c8b244..1e59762 100644 --- a/NativeLibs/yasio/yasio/bindings/yasio_jsb20.cpp +++ b/NativeLibs/yasio/yasio/bindings/yasio_jsb20.cpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -27,16 +27,25 @@ SOFTWARE. */ #define YASIO_HEADER_ONLY 1 #define YASIO_HAVE_KCP 1 +#define YASIO_ENABLE_KCP 1 #define YASIO_OBS_BUILTIN_STACK 1 #include "yasio/yasio.hpp" #include "yasio/ref_ptr.hpp" +#if __has_include() +# include "cocos-version.h" +#endif + #if __has_include() || defined(YASIO_CREATOR_30_OR_LATER) # include "cocos/bindings/jswrapper/SeApi.h" # include "cocos/bindings/manual/jsb_conversions.h" # include "cocos/bindings/manual/jsb_global.h" -# include "cocos/platform/Application.h" +# if __has_include() +# include "cocos/platform/Application.h" +# elif __has_include() +# include "cocos/application/ApplicationManager.h" +# endif # include "cocos/base/Scheduler.h" # include "cocos/base/StringUtil.h" using namespace cc; @@ -86,6 +95,13 @@ enum BUFFER_FAST, }; +// since 3.5 use ApplicationManager +#if defined(COCOS_MAJOR_VERSION) && COCOS_MAJOR_VERSION >= 3 && COCOS_MINJOR_VERSION >= 5 +# define YASIO_JSB_SCHE CC_CURRENT_ENGINE()->getScheduler() +#else +# define YASIO_JSB_SCHE Application::getInstance()->getScheduler() +#endif + namespace stimer { // The STIMER fake target: 0xfffffffe, well, any system's malloc never return a object address @@ -101,7 +117,7 @@ struct TimerObject { vcallback_t callback_; static uintptr_t s_timerId; - DEFINE_OBJECT_POOL_ALLOCATION(TimerObject, 128) + DEFINE_CONCURRENT_OBJECT_POOL_ALLOCATION(TimerObject, 128) YASIO_DEFINE_REFERENCE_CLASS }; uintptr_t TimerObject::s_timerId = 0; @@ -116,7 +132,7 @@ TIMER_ID loop(unsigned int n, float interval, vcallback_t callback) std::string key = StringUtil::format("STMR#%p", timerId); - Application::getInstance()->getScheduler()->schedule( + YASIO_JSB_SCHE->schedule( [timerObj](float /*dt*/) { // lambda expression hold the reference of timerObj automatically. timerObj->callback_(); }, @@ -135,7 +151,7 @@ TIMER_ID delay(float delay, vcallback_t callback) auto timerId = reinterpret_cast(++TimerObject::s_timerId); std::string key = StringUtil::format("STMR#%p", timerId); - Application::getInstance()->getScheduler()->schedule( + YASIO_JSB_SCHE->schedule( [timerObj](float /*dt*/) { // lambda expression hold the reference of timerObj automatically. timerObj->callback_(); }, @@ -149,9 +165,9 @@ TIMER_ID delay(float delay, vcallback_t callback) void kill(TIMER_ID timerId) { std::string key = StringUtil::format("STMR#%p", timerId); - Application::getInstance()->getScheduler()->unschedule(key, STIMER_TARGET_VALUE); + YASIO_JSB_SCHE->unschedule(key, STIMER_TARGET_VALUE); } -void clear() { Application::getInstance()->getScheduler()->unscheduleAllForTarget(STIMER_TARGET_VALUE); } +void clear() { YASIO_JSB_SCHE->unscheduleAllForTarget(STIMER_TARGET_VALUE); } } // namespace stimer } // namespace yasio_jsb @@ -182,8 +198,8 @@ bool jsb_yasio_setTimeout(se::State& s) } }; - float timeout = 0; - seval_to_float(arg1, &timeout); + float timeout = arg1.toFloat(); + auto timerId = yasio_jsb::stimer::delay(timeout, std::move(callback)); s.rval().setNumber((double)(int64_t)timerId); @@ -222,8 +238,7 @@ bool jsb_yasio_setInterval(se::State& s) } }; - float interval = 0; - seval_to_float(arg1, &interval); + float interval = arg1.toFloat(); auto timerId = yasio_jsb::stimer::loop((std::numeric_limits::max)(), interval, std::move(callback)); s.rval().setNumber((double)(int64_t)timerId); @@ -340,36 +355,49 @@ cxx17::string_view seval_to_string_view(const se::Value& v, bool* unrecognized_o //////////////////// common template functions ////////////// +#if defined(JSB_MAKE_PRIVATE_OBJECT) +#define YASIO_JSB_USE_SHARED_OBJECT 1 +# define yasio_jsb_make_object(kls, ...) JSB_MAKE_PRIVATE_OBJECT(kls, __VA_ARGS__) +#else +# define yasio_jsb_make_object(kls, ...) new kls(__VA_ARGS__) +#endif + template static bool jsb_yasio__ctor(se::State& s) { - auto cobj = new T(); + auto cobj = yasio_jsb_make_object(T); +#if defined(YASIO_JSB_USE_SHARED_OBJECT) + s.thisObject()->setPrivateObject(cobj); +#else s.thisObject()->setPrivateData(cobj); se::NonRefNativePtrCreatedByCtorMap::emplace(cobj); +#endif return true; } template static bool jsb_yasio__dtor(se::State& s) { +#if !defined(JSB_MAKE_PRIVATE_OBJECT) auto iter = se::NonRefNativePtrCreatedByCtorMap::find(s.nativeThisObject()); if (iter != se::NonRefNativePtrCreatedByCtorMap::end()) - { + { // finalize created by ctor < 3.6.0 CC_LOG_DEBUG("jsbindings: finalizing JS object(created by ctor) %p(%s)", s.nativeThisObject(), typeid(T).name()); se::NonRefNativePtrCreatedByCtorMap::erase(iter); T* cobj = reinterpret_cast(s.nativeThisObject()); delete cobj; + return true; } - else - { // finalize not created by ctor - auto iter2 = se::NativePtrToObjectMap::find(s.nativeThisObject()); - if (iter2 != se::NativePtrToObjectMap::end()) - { - CC_LOG_DEBUG("jsbindings: finalizing JS object(created by native) %p(%s)", s.nativeThisObject(), typeid(T).name()); - T* cobj = reinterpret_cast(s.nativeThisObject()); - delete cobj; - } +#else + // finalize not created by ctor + auto iter2 = se::NativePtrToObjectMap::find(s.nativeThisObject()); + if (iter2 != se::NativePtrToObjectMap::end()) + { + CC_LOG_DEBUG("jsbindings: finalizing JS object(created by native) %p(%s)", s.nativeThisObject(), typeid(T).name()); + T* cobj = reinterpret_cast(s.nativeThisObject()); + delete cobj; } +#endif return true; } @@ -604,22 +632,22 @@ static bool jsb_yasio_obstream__ctor(se::State& s) const auto& args = s.args(); size_t argc = args.size(); - yasio::obstream* cobj = nullptr; - if (argc == 0) - { - cobj = new yasio::obstream(); - } - else + int capacity = 128; + if (argc >= 1) { auto arg0 = args[0]; if (arg0.isNumber()) - cobj = new yasio::obstream(arg0.toUint32()); - else - cobj = new yasio::obstream(); + capacity = arg0.toUint32(); } + auto cobj = yasio_jsb_make_object(yasio::obstream, capacity); + +#if defined(YASIO_JSB_USE_SHARED_OBJECT) + s.thisObject()->setPrivateObject(cobj); +#else s.thisObject()->setPrivateData(cobj); se::NonRefNativePtrCreatedByCtorMap::emplace(cobj); +#endif return true; } @@ -795,8 +823,12 @@ static bool js_yasio_obstream_write_dx(se::State& s) const auto& args = s.args(); size_t argc = args.size(); +#if defined(COCOS_MAJOR_VERSION) && COCOS_MAJOR_VERSION >= 3 && COCOS_MINJOR_VERSION >= 6 + double argval = args[0].toDouble(); +#else double argval = 0; seval_to_double(args[0], &argval); +#endif cobj->write(static_cast(argval)); s.rval().setUndefined(); @@ -894,10 +926,8 @@ bool js_yasio_obstream_sub(se::State& s) { count = args[1].toInt32(); } - auto subobj = new yasio::obstream(cobj->sub(offset, count)); native_ptr_to_seval(subobj, &s.rval()); - return true; } while (false); @@ -1003,11 +1033,11 @@ bool js_yasio_io_event_packet(se::State& s) case yasio_jsb::BUFFER_RAW: s.rval().setObject(se::HandleObject(se::Object::createArrayBufferObject(packet.data(), packet.size()))); break; - case yasio_jsb::BUFFER_FAST: - native_ptr_to_seval(new yasio::ibstream(yasio::forward_packet((yasio::packet &&) packet)), &s.rval()); + case yasio_jsb::BUFFER_FAST: // fast_ibstream also require export otherwise will assert fail + // native_ptr_to_seval(new yasio::fast_ibstream(yasio::forward_packet((yasio::packet_t &&) packet)), &s.rval()); break; default: - native_ptr_to_seval(new yasio::fast_ibstream(yasio::forward_packet((yasio::packet &&) packet)), &s.rval()); + native_ptr_to_seval(new yasio::ibstream(yasio::forward_packet((yasio::packet_t &&) packet)), &s.rval()); } } else @@ -1083,7 +1113,11 @@ se::Class* __jsb_yasio_io_service_class = nullptr; static bool jsb_yasio_io_service__ctor(se::State& s) { +#if defined(YASIO_JSB_USE_SHARED_OBJECT) + se::PrivateObjectBase* cobj = nullptr; + #else io_service* cobj = nullptr; + #endif const auto& args = s.args(); size_t argc = args.size(); @@ -1096,23 +1130,28 @@ static bool jsb_yasio_io_service__ctor(se::State& s) { std::vector hostents; seval_to_std_vector_hostent(arg0, &hostents); - cobj = new io_service(!hostents.empty() ? &hostents.front() : nullptr, (std::max)((int)hostents.size(), 1)); + cobj = yasio_jsb_make_object(io_service, !hostents.empty() ? &hostents.front() : nullptr, (std::max)((int)hostents.size(), 1)); } else { inet::io_hostent ioh; seval_to_hostent(arg0, &ioh); - cobj = new io_service(&ioh, 1); + cobj = yasio_jsb_make_object(io_service, &ioh, 1); } } else if (arg0.isNumber()) - cobj = new io_service(arg0.toInt32()); + cobj = yasio_jsb_make_object(io_service, arg0.toInt32()); } else - cobj = new io_service(); + cobj = yasio_jsb_make_object(io_service); +#if defined(YASIO_JSB_USE_SHARED_OBJECT) + s.thisObject()->setPrivateObject(cobj); +#else s.thisObject()->setPrivateData(cobj); se::NonRefNativePtrCreatedByCtorMap::emplace(cobj); +#endif + return true; } @@ -1499,10 +1538,14 @@ bool jsb_register_yasio(se::Object* obj) // ##-- yasio enums se::Value __jsvalIntVal; -#define YASIO_SET_INT_PROP(name, value) \ +#define YASIO_EXPORT_ENUM(value) \ __jsvalIntVal.setInt32(value); \ - yasio->setProperty(name, __jsvalIntVal) -#define YASIO_EXPORT_ENUM(v) YASIO_SET_INT_PROP(#v, v) + yasio->setProperty(#value, __jsvalIntVal) + +#define YASIO_EXPORT_STR(value) \ + __jsvalIntVal.setString(value); \ + yasio->setProperty(#value, __jsvalIntVal) + YASIO_EXPORT_ENUM(YCK_TCP_CLIENT); YASIO_EXPORT_ENUM(YCK_TCP_SERVER); YASIO_EXPORT_ENUM(YCK_UDP_CLIENT); @@ -1554,6 +1597,10 @@ bool jsb_register_yasio(se::Object* obj) YASIO_EXPORT_ENUM(SEEK_SET); YASIO_EXPORT_ENUM(SEEK_END); + char version[32]; + snprintf(version, sizeof(version), "%x.%x.%x", (YASIO_VERSION_NUM >> 16) & 0xff, (YASIO_VERSION_NUM >> 8) & 0xff, YASIO_VERSION_NUM & 0xff); + YASIO_EXPORT_STR(version); + using namespace yasio_jsb; YASIO_EXPORT_ENUM(BUFFER_DEFAULT); YASIO_EXPORT_ENUM(BUFFER_RAW); diff --git a/NativeLibs/yasio/yasio/bindings/yasio_jsb20.hpp b/NativeLibs/yasio/yasio/bindings/yasio_jsb20.hpp index 27ce488..31093e2 100644 --- a/NativeLibs/yasio/yasio/bindings/yasio_jsb20.hpp +++ b/NativeLibs/yasio/yasio/bindings/yasio_jsb20.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/bindings/yasio_ni.cpp b/NativeLibs/yasio/yasio/bindings/yasio_ni.cpp index 181ef58..94f32f5 100644 --- a/NativeLibs/yasio/yasio/bindings/yasio_ni.cpp +++ b/NativeLibs/yasio/yasio/bindings/yasio_ni.cpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -77,21 +77,32 @@ YASIO_NI_API void yasio_init_globals(void(YASIO_INTEROP_DECL* pfn)(int level, co } YASIO_NI_API void yasio_cleanup_globals() { io_service::cleanup_globals(); } -struct yasio_event_data { - int kind; - int status; - int channel; - void* session; // transport - void* packet; - void* user; // event source +struct yasio_io_event { + int kind; // + int channel; + void* thandle; + union { + void* msg; + int status; // + }; + void* user; }; -YASIO_NI_API void* yasio_create_service(int channel_count, void(YASIO_INTEROP_DECL* event_cb)(yasio_event_data* event), void* user) + +YASIO_NI_API void* yasio_create_service(int channel_count, void(YASIO_INTEROP_DECL* event_cb)(yasio_io_event* event), void* user) { assert(!!event_cb); io_service* service = new io_service(channel_count); service->start([=](event_ptr e) { auto& pkt = e->packet(); - yasio_event_data event{e->kind(), e->status(), e->cindex(), e->transport(), !is_packet_empty(pkt) ? &pkt : nullptr, user}; + yasio_io_event event; + event.kind = e->kind(); + event.channel = e->cindex(); + event.thandle = e->transport(); + event.user = user; + if (event.kind == yasio::YEK_ON_PACKET) + event.msg = !is_packet_empty(pkt) ? &pkt : nullptr; + else + event.status = e->status(); event_cb(&event); }); return service; @@ -232,22 +243,24 @@ YASIO_NI_API void yasio_close_handle(void* service_ptr, void* thandle) if (service) service->close(reinterpret_cast(thandle)); } -YASIO_NI_API int yasio_write(void* service_ptr, void* thandle, const unsigned char* bytes, int len) +YASIO_NI_API int yasio_write(void* service_ptr, void* thandle, const char* bytes, int len) { auto service = reinterpret_cast(service_ptr); if (service) - return service->write(reinterpret_cast(thandle), yasio::sbyte_buffer(bytes, bytes + len, std::true_type{})); + return service->write(reinterpret_cast(thandle), yasio::sbyte_buffer(bytes, bytes + len)); return -1; } -YASIO_NI_API int yasio_forward(void* service_ptr, void* thandle, void* bufferHandle, const unsigned char*(YASIO_INTEROP_DECL* pfnLockBuffer)(void* bufferHandle, int* bufferDataLen), void(YASIO_INTEROP_DECL* pfnUnlockBuffer)(void* bufferHandle)) +YASIO_NI_API int yasio_forward(void* service_ptr, void* thandle, void* bufferHandle, + const char*(YASIO_INTEROP_DECL* pfnLockBuffer)(void* bufferHandle, int* bufferDataLen), + void(YASIO_INTEROP_DECL* pfnUnlockBuffer)(void* bufferHandle)) { auto service = reinterpret_cast(service_ptr); - if (service) { - int len = 0; + if (service) + { + int len = 0; auto bytes = pfnLockBuffer(bufferHandle, &len); - return service->forward(reinterpret_cast(thandle), bytes, len, [bufferHandle,pfnUnlockBuffer](int,size_t){ - pfnUnlockBuffer(bufferHandle); - }); + return service->forward(reinterpret_cast(thandle), bytes, len, + [bufferHandle, pfnUnlockBuffer](int, size_t) { pfnUnlockBuffer(bufferHandle); }); } return -1; } diff --git a/NativeLibs/yasio/yasio/bindings/yasio_sol.hpp b/NativeLibs/yasio/yasio/bindings/yasio_sol.hpp index 8de03fc..8945df6 100644 --- a/NativeLibs/yasio/yasio/bindings/yasio_sol.hpp +++ b/NativeLibs/yasio/yasio/bindings/yasio_sol.hpp @@ -4,7 +4,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/NativeLibs/yasio/yasio/buffer_alloc.hpp b/NativeLibs/yasio/yasio/buffer_alloc.hpp new file mode 100644 index 0000000..8947804 --- /dev/null +++ b/NativeLibs/yasio/yasio/buffer_alloc.hpp @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef YASIO__BUFFER_ALLOC_HPP +#define YASIO__BUFFER_ALLOC_HPP +#include +#include +#include +#include +#include +#include "yasio/compiler/feature_test.hpp" +#include "yasio/type_traits.hpp" + +#define _YASIO_VERIFY_RANGE(cond, mesg) \ + do \ + { \ + if (cond) \ + ; /* contextually convertible to bool paranoia */ \ + else \ + { \ + throw std::out_of_range(mesg); \ + } \ + \ + } while (false) + +namespace yasio +{ +template +struct buffer_allocator_traits { + using value_type = typename _Alty::value_type; + using size_type = size_t; + static YASIO__CONSTEXPR size_type max_size() { return static_cast(-1) / sizeof(value_type); } + static value_type* reallocate(void* block, size_t size, size_t new_size) + { + return static_cast(_Alty::reallocate(block, size, new_size * sizeof(value_type))); + } + static void deallocate(void* block, size_t size) { _Alty::deallocate(block, size); } +}; +template ::value, int> = 0> +struct buffer_allocator { + using value_type = _Ty; + static value_type* reallocate(void* block, size_t /*size*/, size_t new_size) + { + return static_cast(::realloc(block, new_size * sizeof(value_type))); + } + static void deallocate(void* block, size_t /*size*/) { ::free(block); } +}; +template ::value, int> = 0> +struct std_buffer_allocator { + using value_type = _Ty; + static value_type* reallocate(void* block, size_t size, size_t new_size) + { + if (!block) + return new (std::nothrow) value_type[new_size]; + void* new_block = nullptr; + if (new_size) + { + if (new_size <= size) + return block; + new_block = new (std::nothrow) value_type[new_size]; + if (new_block) + memcpy(new_block, block, size); + } + delete[] (value_type*)block; + return (value_type*)new_block; + } + static void deallocate(void* block, size_t /*size*/) { delete[] (value_type*)block; } +}; +template +struct construct_helper { + template + static _Ty* construct_at(_Ty* p, Args&&... args) + { + return ::new (static_cast(p)) _Ty(std::forward(args)...); + } +}; +template +struct construct_helper<_Ty, false> { + template + static _Ty* construct_at(_Ty* p, Args&&... args) + { + return ::new (static_cast(p)) _Ty{std::forward(args)...}; + } +}; + +template +inline _Ty* construct_at(_Ty* p, Args&&... args) +{ + return construct_helper<_Ty, std::is_constructible<_Ty, Args&&...>::value>::construct_at(p, std::forward(args)...); +} + +} // namespace yasio + +#endif diff --git a/NativeLibs/yasio/yasio/byte_buffer.hpp b/NativeLibs/yasio/yasio/byte_buffer.hpp index 7363709..837461e 100644 --- a/NativeLibs/yasio/yasio/byte_buffer.hpp +++ b/NativeLibs/yasio/yasio/byte_buffer.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -24,413 +24,19 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Version: 3.39.5 - -The byte_buffer concepts: - a. The memory model is similar to to std::vector, std::string - b. Support resize fit - c. By default resize without fill (uninitialized and for overwrite) - d. Support release internal buffer ownership with `release_pointer` - e. Since 3.39.5, default allocator use new/delete instead `malloc/free` - - yasio::default_byte_allocator (new/delete) - - yasio::crt_byte_allocator (malloc/free) */ #ifndef YASIO__BYTE_BUFFER_HPP #define YASIO__BYTE_BUFFER_HPP -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "yasio/compiler/feature_test.hpp" +#include "yasio/pod_vector.hpp" namespace yasio { -#define _YASIO_VERIFY_RANGE(cond, mesg) \ - do \ - { \ - if (cond) \ - ; /* contextually convertible to bool paranoia */ \ - else \ - { \ - throw std::out_of_range(mesg); \ - } \ - \ - } while (false) - -template -using enable_if_t = typename ::std::enable_if<_Test, _Ty>::type; - -template -struct is_byte_type { - static const bool value = - std::is_same<_Elem, char>::value || std::is_same<_Elem, unsigned char>::value; -}; - -template ::value, int> = 0> -struct default_byte_allocator { - static _Elem* allocate(size_t count) { return new _Elem[count]; } - static void deallocate(_Elem* pBlock, size_t) { delete[] pBlock; } -}; - -template ::value, int> = 0> -struct crt_byte_allocator { - static _Elem* allocate(size_t count) { return malloc(count); } - static void deallocate(_Elem* pBlock, size_t) { free(pBlock); } -}; - -template , - enable_if_t::value, int> = 0> -class basic_byte_buffer { -public: - using pointer = _Elem*; - using const_pointer = const _Elem*; - using reference = _Elem&; - using const_reference = const _Elem&; - using size_type = size_t; - using value_type = _Elem; - using iterator = _Elem*; // byte_buffer only needs transparent iterator - using const_iterator = const _Elem*; - using allocator_type = _Alloc; - basic_byte_buffer() {} - explicit basic_byte_buffer(size_type count) { resize(count); } - basic_byte_buffer(size_type count, std::true_type /*fit*/) { resize_fit(count); } - basic_byte_buffer(size_type count, const_reference val) { resize(count, val); } - basic_byte_buffer(size_type count, const_reference val, std::true_type /*fit*/) - { - resize_fit(count, val); - } - template - basic_byte_buffer(_Iter first, _Iter last) - { - assign(first, last); - } - template - basic_byte_buffer(_Iter first, _Iter last, std::true_type /*fit*/) - { - assign(first, last, std::true_type{}); - } - basic_byte_buffer(const basic_byte_buffer& rhs) { assign(rhs); }; - basic_byte_buffer(const basic_byte_buffer& rhs, std::true_type /*fit*/) - { - assign(rhs, std::true_type{}); - } - basic_byte_buffer(basic_byte_buffer&& rhs) YASIO__NOEXCEPT { assign(std::move(rhs)); } - template ::value, int> = 0> - basic_byte_buffer(std::initializer_list<_Ty> rhs) - { - assign(rhs); - } - template ::value, int> = 0> - basic_byte_buffer(std::initializer_list<_Ty> rhs, std::true_type /*fit*/) - { - assign(rhs, std::true_type{}); - } - ~basic_byte_buffer() { _Tidy(); } - basic_byte_buffer& operator=(const basic_byte_buffer& rhs) - { - assign(rhs); - return *this; - } - basic_byte_buffer& operator=(basic_byte_buffer&& rhs) YASIO__NOEXCEPT - { - this->swap(rhs); - return *this; - } - template - basic_byte_buffer& operator+=(const _Cont& rhs) - { - return this->append(std::begin(rhs), std::end(rhs)); - } - basic_byte_buffer& operator+=(const_reference rhs) - { - this->push_back(rhs); - return *this; - } - template - void assign(const _Iter first, const _Iter last) - { - _Assign_range(first, last); - } - template - void assign(const _Iter first, const _Iter last, std::true_type /*fit*/) - { - _Assign_range(first, last, std::true_type{}); - } - void assign(const basic_byte_buffer& rhs) { _Assign_range(rhs.begin(), rhs.end()); } - void assign(const basic_byte_buffer& rhs, std::true_type) - { - _Assign_range(rhs.begin(), rhs.end(), std::true_type{}); - } - void assign(basic_byte_buffer&& rhs) { _Assign_rv(std::move(rhs)); } - template ::value, int> = 0> - void assign(std::initializer_list<_Ty> rhs) - { - _Assign_range((iterator)rhs.begin(), (iterator)rhs.end()); - } - template ::value, int> = 0> - void assign(std::initializer_list<_Ty> rhs, std::true_type /*fit*/) - { - _Assign_range((iterator)rhs.begin(), (iterator)rhs.end(), std::true_type{}); - } - void swap(basic_byte_buffer& rhs) YASIO__NOEXCEPT - { - std::swap(_Myfirst, rhs._Myfirst); - std::swap(_Mylast, rhs._Mylast); - std::swap(_Myend, rhs._Myend); - } - template - iterator insert(iterator _Where, _Iter first, const _Iter last) - { - _YASIO_VERIFY_RANGE(_Where >= _Myfirst && _Where <= _Mylast && first <= last, - "byte_buffer: out of range!"); - if (first != last) - { - auto ifirst = (iterator)std::addressof(*first); - auto ilast = (iterator)(std::addressof(*first) + std::distance(first, last)); - auto count = std::distance(ifirst, ilast); - auto insertion_pos = std::distance(_Myfirst, _Where); - if (_Where == _Mylast) - { - if (count > 1) - { - auto old_size = _Mylast - _Myfirst; - resize(old_size + count); - std::copy_n(ifirst, count, _Myfirst + old_size); - } - else if (count == 1) - push_back(static_cast(*ifirst)); - } - else - { - if (insertion_pos >= 0) - { - auto old_size = _Mylast - _Myfirst; - resize(old_size + count); - _Where = _Myfirst + insertion_pos; - auto move_to = _Where + count; - std::copy_n(_Where, _Mylast - move_to, move_to); - std::copy_n(ifirst, count, _Where); - } - } - return _Myfirst + insertion_pos; - } - return _Where; - } - template - basic_byte_buffer& append(_Iter first, const _Iter last) - { - insert(end(), first, last); - return *this; - } - void push_back(value_type v) - { - resize(this->size() + 1); - *(_Mylast - 1) = v; - } - iterator erase(iterator _Where) - { - _YASIO_VERIFY_RANGE(_Where >= _Myfirst && _Where < _Mylast, "byte_buffer: out of range!"); - _Mylast = std::move(_Where + 1, _Mylast, _Where); - return _Where; - } - iterator erase(iterator first, iterator last) - { - _YASIO_VERIFY_RANGE((first <= last) && first >= _Myfirst && last <= _Mylast, - "byte_buffer: out of range!"); - _Mylast = std::move(last, _Mylast, first); - return first; - } - value_type& front() - { - _YASIO_VERIFY_RANGE(_Myfirst < _Mylast, "byte_buffer: out of range!"); - return *_Myfirst; - } - value_type& back() - { - _YASIO_VERIFY_RANGE(_Myfirst < _Mylast, "byte_buffer: out of range!"); - return *(_Mylast - 1); - } - static YASIO__CONSTEXPR size_type max_size() YASIO__NOEXCEPT - { - return (std::numeric_limits::max)(); - } - iterator begin() YASIO__NOEXCEPT { return _Myfirst; } - iterator end() YASIO__NOEXCEPT { return _Mylast; } - const_iterator begin() const YASIO__NOEXCEPT { return _Myfirst; } - const_iterator end() const YASIO__NOEXCEPT { return _Mylast; } - pointer data() YASIO__NOEXCEPT { return _Myfirst; } - const_pointer data() const YASIO__NOEXCEPT { return _Myfirst; } - size_type capacity() const YASIO__NOEXCEPT { return static_cast(_Myend - _Myfirst); } - size_type size() const YASIO__NOEXCEPT { return static_cast(_Mylast - _Myfirst); } - void clear() YASIO__NOEXCEPT { _Mylast = _Myfirst; } - bool empty() const YASIO__NOEXCEPT { return _Mylast == _Myfirst; } - const_reference operator[](size_type index) const { return this->at(index); } - reference operator[](size_type index) { return this->at(index); } - const_reference at(size_type index) const - { - _YASIO_VERIFY_RANGE(index < this->size(), "byte_buffer: out of range!"); - return _Myfirst[index]; - } - reference at(size_type index) - { - _YASIO_VERIFY_RANGE(index < this->size(), "byte_buffer: out of range!"); - return _Myfirst[index]; - } - void resize(size_type new_size, const_reference val) - { - auto old_size = this->size(); - resize(new_size); - if (old_size < new_size) - memset(_Myfirst + old_size, val, new_size - old_size); - } - void resize(size_type new_size) - { - auto old_cap = this->capacity(); - if (old_cap < new_size) - _Reallocate_exactly(_Calculate_growth(new_size), new_size); - else - _Mylast = _Myfirst + new_size; - } - void resize_fit(size_type new_size, const_reference val) - { - auto old_size = this->size(); - resize_fit(new_size); - if (old_size < new_size) - memset(_Myfirst + old_size, val, new_size - old_size); - } - void resize_fit(size_type new_size) - { - if (this->capacity() < new_size) - _Reallocate_exactly(new_size, new_size); - else - _Mylast = _Myfirst + new_size; - } - void reserve(size_type new_cap) - { - if (this->capacity() < new_cap) - _Reallocate_exactly(new_cap, this->size()); - } - void shrink_to_fit() - { // reduce capacity to size, provide strong guarantee - const pointer _Oldlast = _Mylast; - if (_Oldlast != _Myend) - { // something to do - const pointer _Oldfirst = _Myfirst; - if (_Oldfirst == _Oldlast) - _Tidy(); - else - { - const auto _OldSize = static_cast(_Oldlast - _Oldfirst); - _Reallocate_exactly(_OldSize, _OldSize); - } - } - } - /** Release internal buffer ownership - * Note: this is a unsafe operation, after take the internal buffer, you are responsible for - * destroy it once you don't need it, i.e: - * yasio::byte_buffer buf; - * buf.push_back('I'); - * auto rawbufCapacity = buf.capacity(); - * auto rawbufLen = buf.size(); - * auto rawbuf = buf.release_pointer(); - * // use rawbuf to do something - * // ... - * // done, destroy the memory - * yasio::byte_buffer::allocator_type::deallocate(rawbuf, rawbufCapacity); - * - */ - pointer release_pointer() YASIO__NOEXCEPT - { - auto ptr = _Myfirst; - _Myfirst = nullptr; - _Mylast = nullptr; - _Myend = nullptr; - return ptr; - } +template , enable_if_t::value, int> = 0> +using basic_byte_buffer = array_buffer<_Ty, _Alloc>; -private: - template - void _Assign_range(_Iter first, _Iter last) - { - _Mylast = _Myfirst; - if (last > first) - { - auto ifirst = (iterator)std::addressof(*first); - auto ilast = (iterator)std::addressof(*last); - resize(std::distance(ifirst, ilast)); - std::copy(ifirst, ilast, _Myfirst); - } - } - template - void _Assign_range(_Iter first, _Iter last, std::true_type) - { - _Mylast = _Myfirst; - if (last > first) - { - resize_fit(std::distance(first, last)); - std::copy(first, last, _Myfirst); - } - } - void _Assign_rv(basic_byte_buffer&& rhs) - { - memcpy(this, &rhs, sizeof(rhs)); - memset(&rhs, 0, sizeof(rhs)); - } - void _Reallocate_exactly(size_type new_cap, size_type new_size) - { - const pointer _Newvec = _Alloc::allocate(new_cap); - if (_Myfirst) - { - std::copy(_Myfirst, _Mylast, _Newvec); - _Alloc::deallocate(_Myfirst, static_cast(_Myend - _Myfirst)); - } - _Myfirst = _Newvec; - _Mylast = _Newvec + new_size; - _Myend = _Newvec + new_cap; - } - size_type _Calculate_growth(const size_type _Newsize) const - { - // given _Oldcapacity and _Newsize, calculate geometric growth - const size_type _Oldcapacity = capacity(); - YASIO__CONSTEXPR auto _Max = max_size(); - - if (_Oldcapacity > _Max - _Oldcapacity / 2) - return _Max; // geometric growth would overflow - - const size_type _Geometric = _Oldcapacity + (_Oldcapacity >> 1); - - if (_Geometric < _Newsize) - return _Newsize; // geometric growth would be insufficient - - return _Geometric; // geometric growth is sufficient - } - void _Tidy() YASIO__NOEXCEPT - { // free all storage - if (_Myfirst) - { // destroy and deallocate old array - _Alloc::deallocate(_Myfirst, static_cast(_Myend - _Myfirst)); - - _Myfirst = nullptr; - _Mylast = nullptr; - _Myend = nullptr; - } - } - - pointer _Myfirst = nullptr; - pointer _Mylast = nullptr; - pointer _Myend = nullptr; -}; using sbyte_buffer = basic_byte_buffer; using byte_buffer = basic_byte_buffer; + } // namespace yasio #endif diff --git a/NativeLibs/yasio/yasio/compiler/feature_test.hpp b/NativeLibs/yasio/yasio/compiler/feature_test.hpp index 2a7123a..42eb79b 100644 --- a/NativeLibs/yasio/yasio/compiler/feature_test.hpp +++ b/NativeLibs/yasio/yasio/compiler/feature_test.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -48,12 +48,10 @@ SOFTWARE. #if !defined(_MSC_VER) || _MSC_VER >= 1900 # define YASIO__HAS_CXX11 1 # define YASIO__NS_INLINE inline -# define YASIO__CONSTEXPR constexpr # define YASIO__NOEXCEPT noexcept #else # define YASIO__HAS_CXX11 0 # define YASIO__NS_INLINE -# define YASIO__CONSTEXPR const # define YASIO__NOEXCEPT throw() #endif @@ -78,6 +76,12 @@ SOFTWARE. # define YASIO__HAS_CXX17 0 #endif +#if YASIO__HAS_CXX17 +# define YASIO__CONSTEXPR constexpr +#else +# define YASIO__CONSTEXPR +#endif + // Tests whether compiler has c++20 support #if (defined(__cplusplus) && __cplusplus > 201703L) || \ (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX20) && _HAS_CXX20 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201703L)))) @@ -172,6 +176,12 @@ SOFTWARE. # define YASIO__HAS_NTOP 0 #endif +#if defined(_WIN32) && (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP)) && !defined(__MINGW64__) && !defined(__MINGW32__) +# define YASIO__HAS_WIN32_TIMEAPI 1 +#else +# define YASIO__HAS_WIN32_TIMEAPI 0 +#endif + // 64bits Sense Macros #if defined(_M_X64) || defined(_WIN64) || defined(__LP64__) || defined(_LP64) || defined(__x86_64) || defined(__arm64__) || defined(__aarch64__) # define YASIO__64BITS 1 diff --git a/NativeLibs/yasio/yasio/config.hpp b/NativeLibs/yasio/yasio/config.hpp index ccb33a0..4f4e5cf 100644 --- a/NativeLibs/yasio/yasio/config.hpp +++ b/NativeLibs/yasio/yasio/config.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -93,6 +93,11 @@ SOFTWARE. */ // #define YASIO_NT_COMPAT_GAI 1 +/* +** Uncomment or add compiler flag -DYASIO_NT_XHRES_TIMER to forcing use undocumented NT API to setup high-resolution timer +*/ +// #define YASIO_NT_XHRES_TIMER 1 + /* ** Uncomment or add compiler flag -DYASIO_MINIFY_EVENT to minfy size of io_event */ @@ -134,9 +139,14 @@ SOFTWARE. */ // #define YASIO_ENABLE_HPERF_IO 1 -#if defined(_WIN32) && defined(YASIO_ENABLE_HPERF_IO) -# undef YASIO__HAS_EPOLL -# define YASIO__HAS_EPOLL 1 +#if defined(_WIN32) +# if defined(YASIO_ENABLE_HPERF_IO) +# undef YASIO__HAS_EPOLL +# define YASIO__HAS_EPOLL 1 +# endif +# if YASIO__HAS_WIN32_TIMEAPI && !defined(YASIO_NT_XHRES_TIMER) +# define YASIO__USE_TIMEAPI 1 +# endif #endif #if defined(YASIO_HEADER_ONLY) @@ -195,7 +205,7 @@ SOFTWARE. /* ** The yasio version macros */ -#define YASIO_VERSION_NUM 0x040100 +#define YASIO_VERSION_NUM 0x050000 /* ** The macros used by io_service. @@ -206,9 +216,6 @@ SOFTWARE. // The default ttl of multicast #define YASIO_DEFAULT_MULTICAST_TTL (int)128 -// The max internet buffer size -#define YASIO_INET_BUFFER_SIZE 65536 - // The max pdu buffer length, avoid large memory allocation when application decode a huge length. #define YASIO_MAX_PDU_BUFFER_SIZE static_cast(1 * 1024 * 1024) diff --git a/NativeLibs/yasio/yasio/endian_portable.hpp b/NativeLibs/yasio/yasio/endian_portable.hpp index 76ea246..bd14f8b 100644 --- a/NativeLibs/yasio/yasio/endian_portable.hpp +++ b/NativeLibs/yasio/yasio/endian_portable.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -31,6 +31,7 @@ SOFTWARE. #include #include #include +#include #ifdef _WIN32 # if !defined(WIN32_LEAN_AND_MEAN) diff --git a/NativeLibs/yasio/yasio/errc.hpp b/NativeLibs/yasio/yasio/errc.hpp index 207c76c..ad696a9 100644 --- a/NativeLibs/yasio/yasio/errc.hpp +++ b/NativeLibs/yasio/yasio/errc.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/ibstream.hpp b/NativeLibs/yasio/yasio/ibstream.hpp index be5649f..b166f62 100644 --- a/NativeLibs/yasio/yasio/ibstream.hpp +++ b/NativeLibs/yasio/yasio/ibstream.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -306,7 +306,7 @@ class basic_ibstream : public binary_reader_impl<_Traits> { auto size = fin.tellg(); if (size > 0) { - blob_.resize_fit(static_cast(size)); + blob_.resize(static_cast(size)); fin.seekg(0, std::ios_base::beg); fin.read(blob_.data(), blob_.size()); this->reset(blob_.data(), static_cast(blob_.size())); diff --git a/NativeLibs/yasio/yasio/impl/ares.hpp b/NativeLibs/yasio/yasio/impl/ares.hpp index f16d5c6..224ab60 100644 --- a/NativeLibs/yasio/yasio/impl/ares.hpp +++ b/NativeLibs/yasio/yasio/impl/ares.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/impl/char_traits.hpp b/NativeLibs/yasio/yasio/impl/char_traits.hpp new file mode 100644 index 0000000..d6bb8c3 --- /dev/null +++ b/NativeLibs/yasio/yasio/impl/char_traits.hpp @@ -0,0 +1,268 @@ +#pragma once +#include + +template +inline size_t __xxtraits_find(const typename _Traits::char_type* _Haystack, const size_t _Hay_size, + const size_t _Start_at, const typename _Traits::char_type* _Needle, + const size_t _Needle_size) +{ // search [_Haystack, _Haystack + + // _Hay_size) for [_Needle, _Needle + + // _Needle_size), at/after _Start_at + if (_Needle_size > _Hay_size || _Start_at > _Hay_size - _Needle_size) + { // xpos cannot exist, report failure + // N4659 24.3.2.7.2 [string.find]/1 says: + // 1. _Start_at <= xpos + // 2. xpos + _Needle_size <= _Hay_size; + // therefore: + // 3. _Needle_size <= _Hay_size (by 2) + // (checked above) + // 4. _Start_at + _Needle_size <= + // _Hay_size (substitute 1 into 2) + // 5. _Start_at <= _Hay_size - + // _Needle_size (4, move _Needle_size to + // other side) (also checked above) + return static_cast(-1); + } + + if (_Needle_size == 0) + { // empty string always matches if xpos is possible + return _Start_at; + } + + const auto _Possible_matches_end = _Haystack + (_Hay_size - _Needle_size) + 1; + for (auto _Match_try = _Haystack + _Start_at;; ++_Match_try) + { + _Match_try = _Traits::find(_Match_try, static_cast(_Possible_matches_end - _Match_try), + *_Needle); + if (!_Match_try) + { // didn't find first character; report failure + return static_cast(-1); + } + + if (_Traits::compare(_Match_try, _Needle, _Needle_size) == 0) + { // found match + return static_cast(_Match_try - _Haystack); + } + } +} + +template +inline size_t __xxtraits_find_ch(const typename _Traits::char_type* _Haystack, + const size_t _Hay_size, const size_t _Start_at, + const typename _Traits::char_type _Ch) +{ // search [_Haystack, _Haystack + _Hay_size) + // for _Ch, at/after _Start_at + if (_Start_at < _Hay_size) + { + const auto _Found_at = _Traits::find(_Haystack + _Start_at, _Hay_size - _Start_at, _Ch); + if (_Found_at) + { + return static_cast(_Found_at - _Haystack); + } + } + + return static_cast(-1); // (npos) no match +} + +template +inline size_t __xxtraits_rfind(const typename _Traits::char_type* _Haystack, const size_t _Hay_size, + const size_t _Start_at, const typename _Traits::char_type* _Needle, + const size_t _Needle_size) +{ // search [_Haystack, _Haystack + _Hay_size) + // for [_Needle, _Needle + _Needle_size) + // beginning before _Start_at + if (_Needle_size == 0) + { + return (std::min)(_Start_at, _Hay_size); // empty string always matches + } + + if (_Needle_size <= _Hay_size) + { // room for match, look for it + for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - _Needle_size);; + --_Match_try) + { + if (_Traits::eq(*_Match_try, *_Needle) && + _Traits::compare(_Match_try, _Needle, _Needle_size) == 0) + { + return static_cast(_Match_try - _Haystack); // found a match + } + + if (_Match_try == _Haystack) + { + break; // at beginning, no more chance for match + } + } + } + + return static_cast(-1); // no match +} + +template +inline size_t __xxtraits_rfind_ch(const typename _Traits::char_type* _Haystack, + const size_t _Hay_size, const size_t _Start_at, + const typename _Traits::char_type _Ch) +{ // search [_Haystack, _Haystack + + // _Hay_size) for _Ch before _Start_at + if (_Hay_size != 0) + { // room for match, look for it + for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - 1);; --_Match_try) + { + if (_Traits::eq(*_Match_try, _Ch)) + { + return static_cast(_Match_try - _Haystack); // found a match + } + + if (_Match_try == _Haystack) + { + break; // at beginning, no more chance for match + } + } + } + + return static_cast(-1); // no match +} + +template +inline size_t __xxtraits_find_last_of(const typename _Traits::char_type* _Haystack, + const size_t _Hay_size, const size_t _Start_at, + const typename _Traits::char_type* _Needle, + const size_t _Needle_size) +{ // in [_Haystack, _Haystack + _Hay_size), look for + // last of [_Needle, _Needle + _Needle_size), before + // _Start_at general algorithm + if (_Needle_size != 0 && _Hay_size != 0) + { // worth searching, do it + for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - 1);; --_Match_try) + { + if (_Traits::find(_Needle, _Needle_size, *_Match_try)) + { + return static_cast(_Match_try - _Haystack); // found a match + } + + if (_Match_try == _Haystack) + { + break; // at beginning, no more chance for match + } + } + } + + return static_cast(-1); // no match +} + +template +inline size_t __xxtraits_find_last_not_of(const typename _Traits::char_type* _Haystack, + const size_t _Hay_size, const size_t _Start_at, + const typename _Traits::char_type* _Needle, + const size_t _Needle_size) +{ // in [_Haystack, _Haystack + _Hay_size), look for + // none of [_Needle, _Needle + _Needle_size), before + // _Start_at general algorithm + if (_Hay_size != 0) + { // worth searching, do it + for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - 1);; --_Match_try) + { + if (!_Traits::find(_Needle, _Needle_size, *_Match_try)) + { + return static_cast(_Match_try - _Haystack); // found a match + } + + if (_Match_try == _Haystack) + { + break; // at beginning, no more chance for match + } + } + } + + return static_cast(-1); // no match +} + +template +inline size_t __xxtraits_find_first_of(const typename _Traits::char_type* _Haystack, + const size_t _Hay_size, const size_t _Start_at, + const typename _Traits::char_type* _Needle, + const size_t _Needle_size) +{ // in [_Haystack, _Haystack + _Hay_size), look for + // one of [_Needle, _Needle + _Needle_size), at/after + // _Start_at general algorithm + if (_Needle_size != 0 && _Start_at < _Hay_size) + { // room for match, look for it + const auto _End = _Haystack + _Hay_size; + for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) + { + if (_Traits::find(_Needle, _Needle_size, *_Match_try)) + { + return (static_cast(_Match_try - _Haystack)); // found a match + } + } + } + + return (static_cast(-1)); // no match +} + +template +inline size_t __xxtraits_find_first_not_of(const typename _Traits::char_type* _Haystack, + const size_t _Hay_size, const size_t _Start_at, + const typename _Traits::char_type* _Needle, + const size_t _Needle_size) +{ // in [_Haystack, _Haystack + _Hay_size), look for none + // of [_Needle, _Needle + _Needle_size), at/after + // _Start_at general algorithm + if (_Start_at < _Hay_size) + { // room for match, look for it + const auto _End = _Haystack + _Hay_size; + for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) + { + if (!_Traits::find(_Needle, _Needle_size, *_Match_try)) + { + return (static_cast(_Match_try - _Haystack)); // found a match + } + } + } + + return (static_cast(-1)); // no match +} + +template +inline size_t __xxtraits_find_not_ch(const typename _Traits::char_type* _Haystack, + const size_t _Hay_size, const size_t _Start_at, + const typename _Traits::char_type _Ch) +{ // search [_Haystack, _Haystack + _Hay_size) for any value other + // than _Ch, at/after _Start_at + if (_Start_at < _Hay_size) + { // room for match, look for it + const auto _End = _Haystack + _Hay_size; + for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) + { + if (!_Traits::eq(*_Match_try, _Ch)) + { + return (static_cast(_Match_try - _Haystack)); // found a match + } + } + } + + return (static_cast(-1)); // no match +} + +template +inline size_t __xxtraits_rfind_not_ch(const typename _Traits::char_type* _Haystack, + const size_t _Hay_size, const size_t _Start_at, + const typename _Traits::char_type _Ch) +{ // search [_Haystack, _Haystack + _Hay_size) for any value other than _Ch before _Start_at + if (_Hay_size != 0) + { // room for match, look for it + for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - 1);; --_Match_try) + { + if (!_Traits::eq(*_Match_try, _Ch)) + { + return (static_cast(_Match_try - _Haystack)); // found a match + } + + if (_Match_try == _Haystack) + { + break; // at beginning, no more chance for match + } + } + } + + return (static_cast(-1)); // no match +} diff --git a/NativeLibs/yasio/yasio/impl/concurrent_queue.hpp b/NativeLibs/yasio/yasio/impl/concurrent_queue.hpp index 8475657..57955fd 100644 --- a/NativeLibs/yasio/yasio/impl/concurrent_queue.hpp +++ b/NativeLibs/yasio/yasio/impl/concurrent_queue.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/impl/epoll_io_watcher.hpp b/NativeLibs/yasio/yasio/impl/epoll_io_watcher.hpp index 239e8b9..0a4b1c0 100644 --- a/NativeLibs/yasio/yasio/impl/epoll_io_watcher.hpp +++ b/NativeLibs/yasio/yasio/impl/epoll_io_watcher.hpp @@ -3,14 +3,14 @@ // client application. ////////////////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) #ifndef YASIO__EPOLL_IO_WATCHER_HPP #define YASIO__EPOLL_IO_WATCHER_HPP #include #include #include +#include "yasio/pod_vector.hpp" #include "yasio/impl/socket.hpp" -#include "yasio/impl/pod_vector.hpp" #include "yasio/impl/select_interrupter.hpp" #if !defined(_WIN32) diff --git a/NativeLibs/yasio/yasio/impl/eventfd_select_interrupter.hpp b/NativeLibs/yasio/yasio/impl/eventfd_select_interrupter.hpp index 900737b..eb5fe28 100644 --- a/NativeLibs/yasio/yasio/impl/eventfd_select_interrupter.hpp +++ b/NativeLibs/yasio/yasio/impl/eventfd_select_interrupter.hpp @@ -3,7 +3,7 @@ // client application. ////////////////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // diff --git a/NativeLibs/yasio/yasio/impl/evport_io_watcher.hpp b/NativeLibs/yasio/yasio/impl/evport_io_watcher.hpp index 66c00cb..6a9de85 100644 --- a/NativeLibs/yasio/yasio/impl/evport_io_watcher.hpp +++ b/NativeLibs/yasio/yasio/impl/evport_io_watcher.hpp @@ -3,16 +3,16 @@ // client application. ////////////////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) #ifndef YASIO__EVPORT_IO_WATCHER_HPP #define YASIO__EVPORT_IO_WATCHER_HPP -#include #include #include #include + +#include "yasio/pod_vector.hpp" #include "yasio/impl/socket.hpp" -#include "yasio/impl/pod_vector.hpp" #include "yasio/impl/select_interrupter.hpp" /* diff --git a/NativeLibs/yasio/yasio/impl/fp16.hpp b/NativeLibs/yasio/yasio/impl/fp16.hpp index 7a2a8b7..9d2dac4 100644 --- a/NativeLibs/yasio/yasio/impl/fp16.hpp +++ b/NativeLibs/yasio/yasio/impl/fp16.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/impl/ifaddrs.hpp b/NativeLibs/yasio/yasio/impl/ifaddrs.hpp index a52cdda..07dd908 100644 --- a/NativeLibs/yasio/yasio/impl/ifaddrs.hpp +++ b/NativeLibs/yasio/yasio/impl/ifaddrs.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/impl/inet_ntop.hpp b/NativeLibs/yasio/yasio/impl/inet_ntop.hpp index 8ece50b..3ca6cdd 100644 --- a/NativeLibs/yasio/yasio/impl/inet_ntop.hpp +++ b/NativeLibs/yasio/yasio/impl/inet_ntop.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/impl/kqueue_io_watcher.hpp b/NativeLibs/yasio/yasio/impl/kqueue_io_watcher.hpp index bfe75f8..ff525bf 100644 --- a/NativeLibs/yasio/yasio/impl/kqueue_io_watcher.hpp +++ b/NativeLibs/yasio/yasio/impl/kqueue_io_watcher.hpp @@ -3,17 +3,16 @@ // client application. ////////////////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) #ifndef YASIO__KQUEUE_IO_WATCHER_HPP #define YASIO__KQUEUE_IO_WATCHER_HPP #include #include #include -#include #include #include +#include "yasio/pod_vector.hpp" #include "yasio/impl/socket.hpp" -#include "yasio/impl/pod_vector.hpp" #include "yasio/impl/select_interrupter.hpp" #if defined(__NetBSD__) && __NetBSD_Version__ < 999001500 diff --git a/NativeLibs/yasio/yasio/impl/mbedtls.hpp b/NativeLibs/yasio/yasio/impl/mbedtls.hpp index a5b3279..6a02ab4 100644 --- a/NativeLibs/yasio/yasio/impl/mbedtls.hpp +++ b/NativeLibs/yasio/yasio/impl/mbedtls.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/impl/object_pool.hpp b/NativeLibs/yasio/yasio/impl/object_pool.hpp index 6b05b65..148c348 100644 --- a/NativeLibs/yasio/yasio/impl/object_pool.hpp +++ b/NativeLibs/yasio/yasio/impl/object_pool.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -46,11 +46,6 @@ namespace yasio { namespace detail { -template -struct aligned_storage_size { - static const size_t value = sizeof(typename std::aligned_storage::type); -}; - class object_pool { #if defined(_DEBUG) typedef struct free_link_node { diff --git a/NativeLibs/yasio/yasio/impl/openssl.hpp b/NativeLibs/yasio/yasio/impl/openssl.hpp index d238606..5bacfd6 100644 --- a/NativeLibs/yasio/yasio/impl/openssl.hpp +++ b/NativeLibs/yasio/yasio/impl/openssl.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -49,7 +49,7 @@ YASIO__DECL yssl_ctx_st* yssl_ctx_new(const yssl_options& opts) { int fail_count = -1; if (yasio__valid_str(opts.crtfile_)) - { + { // CAfile for verify fail_count = 0; yssl_splitpath(opts.crtfile_, [&](char* first, char* last) { yssl_split_term null_term(last); @@ -69,6 +69,11 @@ YASIO__DECL yssl_ctx_st* yssl_ctx_new(const yssl_options& opts) return !ok; }); } + /* + * client cert & key not implement yet, since it not common usecase + * SSL_CTX_use_certificate_chain_file + * SSL_CTX_use_PrivateKey_file + */ if (!fail_count) { ::SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, ::SSL_CTX_get_verify_callback(ctx)); @@ -93,6 +98,14 @@ YASIO__DECL yssl_ctx_st* yssl_ctx_new(const yssl_options& opts) if (yasio__valid_str(opts.keyfile_) && ::SSL_CTX_use_PrivateKey_file(ctx, opts.keyfile_, SSL_FILETYPE_PEM) <= 0) YASIO_LOG("[gobal] load server private key file failed!"); + + /* + * If client provide cert, then verify, otherwise skip verify + * Note: if SSL_VERIFY_FAIL_IF_NO_PEER_CERT specified, client must provide + * cert & key which is not common use, means 100% online servers doesn't require + * client to provide cert + */ + ::SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, ::SSL_CTX_get_verify_callback(ctx)); } return ctx; diff --git a/NativeLibs/yasio/yasio/impl/pipe_select_interrupter.hpp b/NativeLibs/yasio/yasio/impl/pipe_select_interrupter.hpp index dba7d66..c5cf304 100644 --- a/NativeLibs/yasio/yasio/impl/pipe_select_interrupter.hpp +++ b/NativeLibs/yasio/yasio/impl/pipe_select_interrupter.hpp @@ -4,7 +4,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// // // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // diff --git a/NativeLibs/yasio/yasio/impl/pod_vector.hpp b/NativeLibs/yasio/yasio/impl/pod_vector.hpp deleted file mode 100644 index 6b65ea3..0000000 --- a/NativeLibs/yasio/yasio/impl/pod_vector.hpp +++ /dev/null @@ -1,259 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// A multi-platform support c++11 library with focus on asynchronous socket I/O for any -// client application. -////////////////////////////////////////////////////////////////////////////////////////// -/* -SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -Copyright (c) 2012-2023 HALX99 - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - The pod_vector concepts: - a. only accept pod types - b. support release memory ownership with `release_pointer` - c. support pod_allocater with C(realloc) or C++(new/delete) -Copy of https://github.com/microsoft/STL/blob/main/stl/inc/vector but for pod types and only provide -'emplace_back' -*/ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -namespace yasio -{ -template -struct pod_allocator { - static _Ty* allocate(size_t count) { return (_Ty*)new uint8_t[count * sizeof(_Ty)]; } - static void deallocate(_Ty* pBlock) { delete[] (uint8_t*)pBlock; } -}; - -template -struct pod_allocator<_Ty, true> { - static _Ty* allocate(size_t count) { return malloc(count * sizeof(_Ty)); } - static void deallocate(_Ty* pBlock) { free(pBlock); } -}; - -template , typename std::enable_if::value, int>::type = 0> -class pod_vector { -public: - using pointer = _Ty*; - using const_pointer = const _Ty*; - using reference = _Ty&; - using const_reference = const _Ty&; - using size_type = size_t; - using value_type = _Ty; - using iterator = _Ty*; // transparent iterator - using const_iterator = const _Ty*; - pod_vector() = default; - explicit pod_vector(size_t count) { resize_fit(count); } - pod_vector(pod_vector const& rhs) { this->assign(rhs); } - pod_vector& operator=(pod_vector const& rhs) - { - this->assign(rhs); - return *this; - } - - pod_vector(pod_vector&& o) YASIO__NOEXCEPT : _Myfirst(o._Myfirst), _Mylast(o._Mylast), _Myend(o._Myend) - { - o._Myfirst = nullptr; - o._Mylast = nullptr; - o._Myend = nullptr; - } - pod_vector& operator=(pod_vector&& o) YASIO__NOEXCEPT - { - this->swap(o); - return *this; - } - - void assign(pod_vector const& rhs) - { - resize_fit(rhs.size()); - if (!rhs.empty()) - std::copy(rhs._Myfirst, rhs._Mylast, _Myfirst); - } - - void swap(pod_vector& rhs) YASIO__NOEXCEPT - { - std::swap(_Myfirst, rhs._Myfirst); - std::swap(_Mylast, rhs._Mylast); - std::swap(_Myend, rhs._Myend); - } - - ~pod_vector() { _Tidy(); } - - template - _Ty& emplace_back(_Valty&&... _Val) YASIO__NOEXCEPT - { - if (_Mylast != _Myend) - return *new (_Mylast++) _Ty(std::forward<_Valty>(_Val)...); - - return *_Emplace_back_reallocate(std::forward<_Valty>(_Val)...); - } - - void reserve(size_t new_cap) - { - if (new_cap > this->capacity()) - _Reallocate_exactly(new_cap); - } - - void resize(size_t new_size) - { - if (this->capacity() < new_size) - _Reallocate_exactly(_Calculate_growth(new_size)); - _Mylast = _Myfirst + new_size; - } - - void resize_fit(size_t new_size) - { - if (this->capacity() < new_size) - _Reallocate_exactly(new_size); - _Mylast = _Myfirst + new_size; - } - - void reset(size_t new_size) - { - resize_fit(new_size); - memset(_Myfirst, 0x0, size() * sizeof(_Ty)); - } - - static YASIO__CONSTEXPR size_t max_size() YASIO__NOEXCEPT { return (std::numeric_limits::max)(); } - iterator begin() YASIO__NOEXCEPT { return _Myfirst; } - iterator end() YASIO__NOEXCEPT { return _Mylast; } - const_iterator begin() const YASIO__NOEXCEPT { return _Myfirst; } - const_iterator end() const YASIO__NOEXCEPT { return _Mylast; } - pointer data() YASIO__NOEXCEPT { return _Myfirst; } - const_pointer data() const YASIO__NOEXCEPT { return _Myfirst; } - size_t capacity() const YASIO__NOEXCEPT { return _Myend - _Myfirst; } - size_t size() const YASIO__NOEXCEPT { return _Mylast - _Myfirst; } - void clear() YASIO__NOEXCEPT { _Mylast = _Myfirst; } - bool empty() const YASIO__NOEXCEPT { return _Mylast == _Myfirst; } - const_reference operator[](size_t index) const { return _Myfirst[index]; } - reference operator[](size_t index) { return _Myfirst[index]; } - - void shrink_to_fit() - { // reduce capacity to size, provide strong guarantee - const pointer _Oldlast = _Mylast; - if (_Oldlast != _Myend) - { // something to do - const pointer _Oldfirst = _Myfirst; - if (_Oldfirst == _Oldlast) - _Tidy(); - else - _Reallocate_exactly(static_cast(_Oldlast - _Oldfirst)); - } - } - - iterator erase(iterator _Where) - { - // _YASIO_VERIFY_RANGE(_Where >= _Myfirst && _Where < _Mylast, "byte_buffer: out of range!"); - _Mylast = std::move(_Where + 1, _Mylast, _Where); - return _Where; - } - - // release memmory ownership - pointer release_pointer() YASIO__NOEXCEPT - { - auto ptr = _Myfirst; - _Myfirst = nullptr; - _Mylast = nullptr; - _Myend = nullptr; - return ptr; - } - -private: - template - pointer _Emplace_back_reallocate(_Valty&&... _Val) - { - const auto _Oldsize = static_cast(_Mylast - _Myfirst); - - if (_Oldsize == max_size()) - throw std::length_error("pod_vector too long"); - - const size_type _Newsize = _Oldsize + 1; - const size_type _Newcapacity = _Calculate_growth(_Newsize); - - const pointer _Newvec = _Alty::allocate(_Newcapacity); - const pointer _Newptr = _Newvec + _Oldsize; - new ((void*)_Newptr) _Ty(std::forward<_Valty>(_Val)...); - - // at back, provide strong guarantee - std::move(_Myfirst, _Mylast, _Newvec); - - _Change_array(_Newvec, _Newsize, _Newcapacity); - return _Newptr; - } - - void _Reallocate_exactly(size_t _Newcapacity) - { - const auto _Size = static_cast(_Mylast - _Myfirst); - - const pointer _Newvec = _Alty::allocate(_Newcapacity); - - std::copy(_Myfirst, _Mylast, _Newvec); - - _Change_array(_Newvec, _Size, _Newcapacity); - } - - void _Change_array(const pointer _Newvec, const size_type _Newsize, const size_type _Newcapacity) - { - if (_Myfirst) - _Alty::deallocate(_Myfirst /*, static_cast(_Myend - _Myfirst)*/); - - _Myfirst = _Newvec; - _Mylast = _Newvec + _Newsize; - _Myend = _Newvec + _Newcapacity; - } - - size_type _Calculate_growth(const size_type _Newsize) const - { - // given _Oldcapacity and _Newsize, calculate geometric growth - const size_type _Oldcapacity = capacity(); - const auto _Max = max_size(); - - if (_Oldcapacity > _Max - _Oldcapacity / 2) - return _Max; // geometric growth would overflow - - const size_type _Geometric = _Oldcapacity + (_Oldcapacity >> 1); - - if (_Geometric < _Newsize) - return _Newsize; // geometric growth would be insufficient - - return _Geometric; // geometric growth is sufficient - } - - void _Tidy() YASIO__NOEXCEPT - { // free all storage - if (_Myfirst) - { // destroy and deallocate old array - _Alty::deallocate(_Myfirst /*, static_cast(_Myend - _Myfirst)*/); - - _Myfirst = nullptr; - _Mylast = nullptr; - _Myend = nullptr; - } - } - - pointer _Myfirst = nullptr; - pointer _Mylast = nullptr; - pointer _Myend = nullptr; -}; -} // namespace yasio diff --git a/NativeLibs/yasio/yasio/impl/poll_io_watcher.hpp b/NativeLibs/yasio/yasio/impl/poll_io_watcher.hpp index aa88555..baa93f0 100644 --- a/NativeLibs/yasio/yasio/impl/poll_io_watcher.hpp +++ b/NativeLibs/yasio/yasio/impl/poll_io_watcher.hpp @@ -3,12 +3,11 @@ // client application. ////////////////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) #ifndef YASIO__POLL_IO_WATCHER_HPP #define YASIO__POLL_IO_WATCHER_HPP -#include +#include "yasio/pod_vector.hpp" #include "yasio/impl/socket.hpp" -#include "yasio/impl/pod_vector.hpp" #include "yasio/impl/select_interrupter.hpp" namespace yasio @@ -92,7 +91,7 @@ class poll_io_watcher { { auto events = add_events & ~remove_events; if (events) - fdset.emplace_back(pollfd{fd, static_cast(events), 0}); + fdset.emplace_back(fd, static_cast(events), static_cast(0)); } } diff --git a/NativeLibs/yasio/yasio/impl/select_interrupter.hpp b/NativeLibs/yasio/yasio/impl/select_interrupter.hpp index d8e2c9c..923835a 100644 --- a/NativeLibs/yasio/yasio/impl/select_interrupter.hpp +++ b/NativeLibs/yasio/yasio/impl/select_interrupter.hpp @@ -3,7 +3,7 @@ // client application. ////////////////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying diff --git a/NativeLibs/yasio/yasio/impl/select_io_watcher.hpp b/NativeLibs/yasio/yasio/impl/select_io_watcher.hpp index 06e9e79..f07787e 100644 --- a/NativeLibs/yasio/yasio/impl/select_io_watcher.hpp +++ b/NativeLibs/yasio/yasio/impl/select_io_watcher.hpp @@ -3,7 +3,7 @@ // client application. ////////////////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) #ifndef YASIO__SELECT_IO_WATCHER_HPP #define YASIO__SELECT_IO_WATCHER_HPP #include diff --git a/NativeLibs/yasio/yasio/impl/socket.hpp b/NativeLibs/yasio/yasio/impl/socket.hpp index 32b1d6c..1d226b4 100644 --- a/NativeLibs/yasio/yasio/impl/socket.hpp +++ b/NativeLibs/yasio/yasio/impl/socket.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/impl/socket_select_interrupter.hpp b/NativeLibs/yasio/yasio/impl/socket_select_interrupter.hpp index 670c068..42c359a 100644 --- a/NativeLibs/yasio/yasio/impl/socket_select_interrupter.hpp +++ b/NativeLibs/yasio/yasio/impl/socket_select_interrupter.hpp @@ -4,7 +4,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// // // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // diff --git a/NativeLibs/yasio/yasio/io_service.cpp b/NativeLibs/yasio/yasio/io_service.cpp index 1aee40b..614b8e3 100644 --- a/NativeLibs/yasio/yasio/io_service.cpp +++ b/NativeLibs/yasio/yasio/io_service.cpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 HAL: Hardware Abstraction Layer X99: Intel X99 Mainboard Platform @@ -44,8 +44,9 @@ SOFTWARE. # include "yasio/ssl.hpp" #endif +#include "yasio/wtimer_hres.hpp" + #if defined(YASIO_ENABLE_KCP) -# include "kcp/ikcp.h" struct yasio_kcp_options { int kcp_conv_ = 0; @@ -137,9 +138,10 @@ namespace { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. -static const highp_time_t yasio__max_wait_usec = 5 * 60 * 1000 * 1000LL; +static const int yasio__max_wait_usec = 5 * 60 * 1000 * 1000LL; // the max transport alloc size static const size_t yasio__max_tsize = (std::max)({sizeof(io_transport_tcp), sizeof(io_transport_udp), sizeof(io_transport_ssl), sizeof(io_transport_kcp)}); +static const int yasio__udp_mss = static_cast((std::numeric_limits::max)() - (sizeof(yasio::ip::ip_hdr_st) + sizeof(yasio::ip::udp_hdr_st))); } // namespace struct yasio__global_state { enum @@ -204,7 +206,7 @@ void highp_timer::cancel() std::chrono::microseconds highp_timer::wait_duration() const { - return std::chrono::duration_cast(this->expire_time_ - service_.time_); + return std::chrono::duration_cast(this->expire_time_ - service_.current_time_); } /// io_send_op @@ -471,12 +473,24 @@ void io_transport::complete_op(io_send_op* op, int error) } void io_transport::set_primitives() { - this->write_cb_ = [this](const void* data, int len, const ip::endpoint*, int& error) { - int n = socket_->send(data, len, YASIO_MSG_FLAG); - if (n < 0) - error = xxsocket::get_last_errno(); - return n; - }; + if (yasio__testbits(ctx_->properties_, YCM_TCP)) + { + this->write_cb_ = [this](const void* data, int len, const ip::endpoint*, int& error) { + int n = socket_->send(data, len, YASIO_MSG_FLAG); + if (n < 0) + error = xxsocket::get_last_errno(); + return n; + }; + } + else // UDP + { + this->write_cb_ = [this](const void* data, int len, const ip::endpoint*, int& error) { + int n = socket_->send(data, (std::min)(len, yasio__udp_mss), YASIO_MSG_FLAG); + if (n < 0) + error = xxsocket::get_last_errno(); + return n; + }; + } this->read_cb_ = [this](void* data, int len, int revent, int& error) { if (revent) { @@ -503,8 +517,9 @@ io_transport_ssl::io_transport_ssl(io_channel* ctx, xxsocket_ptr&& sock) : io_tr int io_transport_ssl::do_ssl_handshake(int& error) { int ret = yssl_do_handshake(ssl_, error); - if (ret == 0) // handshake succeed - { // because we invoke handshake in call_read, so we emit EWOULDBLOCK to mark ssl transport status `ok` + // handshake succeed, because we invoke handshake in call_read, so we emit EWOULDBLOCK to mark ssl transport status `ok` + if (ret == 0 && !error) + { this->state_ = io_base::state::OPENED; this->read_cb_ = [this](void* data, int len, int revent, int& error) { if (revent) @@ -527,7 +542,7 @@ int io_transport_ssl::do_ssl_handshake(int& error) else { // handshake failed, print reason char buf[256] = {0}; - YASIO_KLOGE("[index: %d] do_ssl_handshake fail with %s", ctx_->index_, yssl_strerror(ssl_, ret, buf, sizeof(buf))); + YASIO_KLOGE("[index: %d] do_ssl_handshake fail with: %s", ctx_->index_, yssl_strerror(ssl_, ret, buf, sizeof(buf))); if (yasio__testbits(ctx_->properties_, YCM_CLIENT)) { YASIO_KLOGE("[index: %d] connect server %s failed, ec=%d, detail:%s", ctx_->index_, ctx_->format_destination().c_str(), error, @@ -619,7 +634,7 @@ void io_transport_udp::set_primitives() { this->write_cb_ = [this](const void* data, int len, const ip::endpoint* destination, int& error) { assert(destination); - int n = socket_->sendto(data, len, *destination); + int n = socket_->sendto(data, (std::min)(len, yasio__udp_mss), *destination); if (n < 0) { error = xxsocket::get_last_errno(); @@ -644,9 +659,13 @@ void io_transport_udp::set_primitives() }; } } -int io_transport_udp::handle_input(const char* data, int bytes_transferred, int& /*error*/, highp_time_t&) +int io_transport_udp::handle_input(char* data, int bytes_transferred, int& /*error*/, highp_time_t&) { // pure udp, dispatch to upper layer directly - get_service().fire_event(this->cindex(), io_packet{data, data + bytes_transferred}, this); + auto& service = get_service(); + if (!service.options_.forward_packet_) + service.fire_event(this->cindex(), io_packet{data, data + bytes_transferred}, this); + else + service.forward_packet(this->cindex(), io_packet_view{data, bytes_transferred}, this); return bytes_transferred; } @@ -656,30 +675,49 @@ io_transport_kcp::io_transport_kcp(io_channel* ctx, xxsocket_ptr&& s) : io_trans { auto& kopts = ctx->kcp_options(); this->kcp_ = ::ikcp_create(static_cast(kopts.kcp_conv_), this); - ::ikcp_nodelay(this->kcp_, kopts.kcp_nodelay_, kopts.kcp_interval_ /*kcp max interval is 5000(ms)*/, kopts.kcp_resend_, kopts.kcp_ncwnd_); + ::ikcp_nodelay(this->kcp_, kopts.kcp_nodelay_, kopts.kcp_interval_, kopts.kcp_resend_, kopts.kcp_ncwnd_); ::ikcp_wndsize(this->kcp_, kopts.kcp_sndwnd_, kopts.kcp_rcvwnd_); ::ikcp_setmtu(this->kcp_, kopts.kcp_mtu_); // Because of nodelaying config will change the value. so setting RTO min after call ikcp_nodely. this->kcp_->rx_minrto = kopts.kcp_minrto_; - this->rawbuf_.resize(YASIO_INET_BUFFER_SIZE); + this->rawbuf_.resize(yasio__max_rcvbuf); ::ikcp_setoutput(this->kcp_, [](const char* buf, int len, ::ikcpcb* /*kcp*/, void* user) { auto t = (io_transport_kcp*)user; int ignored_ec = 0; - return t->write_cb_(buf, len, std::addressof(t->ensure_destination()), ignored_ec); + return t->underlaying_write_cb_(buf, len, std::addressof(t->ensure_destination()), ignored_ec); }); } io_transport_kcp::~io_transport_kcp() { ::ikcp_release(this->kcp_); } -int io_transport_kcp::write(io_send_buffer&& buffer, completion_cb_t&& handler) +void io_transport_kcp::set_primitives() { - std::lock_guard lck(send_mtx_); - int nsent = ::ikcp_send(kcp_, buffer.data(), static_cast(buffer.size())); - assert(nsent > 0); - if (handler) - handler(nsent > 0 ? 0 : nsent, nsent); - get_service().wakeup(); - return nsent; + io_transport_udp::set_primitives(); + underlaying_write_cb_ = write_cb_; + write_cb_ = [this](const void* data, int len, const ip::endpoint*, int& error) { + int nsent = ::ikcp_send(kcp_, static_cast(data), len /*(std::min)(static_cast(kcp_->mss), len)*/); + if (nsent > 0) + { + ::ikcp_flush(kcp_); + expire_time_ = 0; + } + else + error = EMSGSIZE; // emit message too long + return nsent; + }; +} +bool io_transport_kcp::do_write(highp_time_t& wait_duration) +{ + bool ret = io_transport_udp::do_write(wait_duration); + + const auto current = static_cast(std::chrono::duration_cast(get_service().current_time_.time_since_epoch()).count()); + if (((IINT32)(current - expire_time_)) >= 0) + { + ::ikcp_update(kcp_, current); + expire_time_ = ::ikcp_check(kcp_, current); + } + + return ret; } int io_transport_kcp::do_read(int revent, int& error, highp_time_t& wait_duration) { @@ -696,82 +734,18 @@ int io_transport_kcp::do_read(int revent, int& error, highp_time_t& wait_duratio } return n; } -int io_transport_kcp::handle_input(const char* buf, int len, int& error, highp_time_t& wait_duration) +int io_transport_kcp::handle_input(char* buf, int len, int& error, highp_time_t& wait_duration) { // ikcp in event always in service thread, so no need to lock if (0 == ::ikcp_input(kcp_, buf, len)) { - this->check_timeout(wait_duration); // call ikcp_check + expire_time_ = 0; return len; } - // simply regards -1,-2,-3 as error and trigger connection lost event. error = yasio::errc::invalid_packet; return -1; } -bool io_transport_kcp::do_write(highp_time_t& wait_duration) -{ - std::lock_guard lck(send_mtx_); - - ::ikcp_update(kcp_, static_cast(::yasio::clock())); - ::ikcp_flush(kcp_); - this->check_timeout(wait_duration); // call ikcp_check - return true; -} -static IINT32 yasio_itimediff(IUINT32 later, IUINT32 earlier) { return static_cast(later - earlier); } -static IUINT32 yasio_ikcp_check(const ikcpcb* kcp, IUINT32 current, IUINT32 waitd_ms) -{ - IUINT32 ts_flush = kcp->ts_flush; - IINT32 tm_flush = 0x7fffffff; - IINT32 tm_packet = 0x7fffffff; - IUINT32 minimal = 0; - struct IQUEUEHEAD* p; - - if (kcp->updated == 0) - return current; - - if (yasio_itimediff(current, ts_flush) < -10000) - ts_flush = current; - - if (yasio_itimediff(current, ts_flush) >= 0) - return current; - - if (kcp->nsnd_que) - return current; - if (kcp->probe) - return current; - - if (kcp->rmt_wnd == 0 && yasio_itimediff(kcp->current, kcp->ts_probe) >= 0) - return current; - - tm_flush = yasio_itimediff(ts_flush, current); - - for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) - { - const IKCPSEG* seg = iqueue_entry(p, const IKCPSEG, node); - IINT32 diff = yasio_itimediff(seg->resendts, current); - if (diff <= 0) - { - return current; - } - if (diff < tm_packet) - tm_packet = diff; - } - - minimal = kcp->nsnd_buf ? static_cast(tm_packet < tm_flush ? tm_packet : tm_flush) : waitd_ms; - - return current + minimal; -} -void io_transport_kcp::check_timeout(highp_time_t& wait_duration) const -{ - auto current = static_cast(::yasio::clock()); - auto expire_time = yasio_ikcp_check(kcp_, current, static_cast(wait_duration / std::milli::den)); - highp_time_t duration = static_cast(expire_time - current) * std::milli::den; - if (duration < 0) - duration = 0; - if (wait_duration > duration) - wait_duration = duration; -} #endif // ------------------------ io_service ------------------------ void io_service::init_globals(const yasio::inet::print_fn2_t& prt) { yasio__shared_globals(prt).cprint_ = prt; } @@ -864,7 +838,7 @@ void io_service::initialize(const io_hostent* channel_eps, int channel_count) ssl_roles_[YSSL_CLIENT] = ssl_roles_[YSSL_SERVER] = nullptr; #endif - this->wait_duration_ = yasio__max_wait_usec; + this->wait_duration_ = this->sched_freq_; // at least one channel if (channel_count < 1) @@ -924,6 +898,7 @@ void io_service::destroy_channels() } void io_service::clear_transports() { + transport_map_.clear(); for (auto transport : transports_) { cleanup_io(transport); @@ -938,10 +913,38 @@ size_t io_service::dispatch(int max_count) this->events_.consume(max_count, options_.on_event_); return this->events_.count(); } + +#if defined(_WIN32) +template +struct minimal_optional { + template + void emplace(_Args&&... args) + { + new (&unintialized_memory_[0]) _Ty(std::forward<_Args>(args)...); + has_value_ = true; + } + ~minimal_optional() + { + if (has_value_) + { + auto p = (_Ty*)&unintialized_memory_[0]; + p->~_Ty(); + } + } + uint8_t unintialized_memory_[sizeof(_Ty)]; + bool has_value_ = false; +}; +#endif void io_service::run() { yasio::set_thread_name("yasio"); +#if defined(_WIN32) + minimal_optional __timer_hres_man; + if (options_.hres_timer_) + __timer_hres_man.emplace(); +#endif + #if defined(YASIO_SSL_BACKEND) init_ssl_context(YSSL_CLIENT); // by default, init ssl client context #endif @@ -950,14 +953,10 @@ void io_service::run() ares_socket_t ares_socks[ARES_GETSOCK_MAXNUM] = {0}; #endif - // Call once at startup - this->ipsv_ = static_cast(xxsocket::getipsv()); - - // Update time for 1st loop - this->update_time(); - do { + this->current_time_ = yasio::steady_clock_t::now(); + auto waitd_usec = get_timeout(this->wait_duration_); // Gets current wait duration #if defined(YASIO_USE_CARES) /** @@ -1141,6 +1140,14 @@ void io_service::handle_close(transport_handle_t thandle) auto error = thandle->error_; const bool client = yasio__testbits(ctx->properties_, YCM_CLIENT); + if (yasio__testbits(ctx->properties_, YCM_UDP)) + transport_map_.erase(thandle->remote_endpoint()); + + if (yasio__testbits(ctx->properties_, YCM_KCP)) + { + if (--nsched_ <= 0) // if no sched transport, reset sched_freq to max wait 5mins + sched_freq_ = yasio__max_wait_usec; + } if (thandle->state_ == io_base::state::OPENED) { // @Because we can't retrive peer endpoint when connect reset by peer, so use id to trace. YASIO_KLOGD("[index: %d] the connection #%u is lost, ec=%d, where=%d, detail:%s", ctx->index_, thandle->id_, error, (int)thandle->error_stage_, @@ -1204,8 +1211,6 @@ int io_service::forward_to(transport_handle_t transport, const void* buf, size_t void io_service::do_connect(io_channel* ctx) { assert(!ctx->remote_eps_.empty()); - if (this->ipsv_ == 0) - this->ipsv_ = static_cast(xxsocket::getipsv()); if (ctx->socket_->is_open()) cleanup_io(ctx); @@ -1502,7 +1507,7 @@ void io_service::do_accept(io_channel* ctx) { if (yasio__testbits(ctx->properties_, YCPF_MCAST)) ctx->join_multicast_group(); - ctx->buffer_.resize(YASIO_INET_BUFFER_SIZE); + ctx->buffer_.resize(yasio__max_rcvbuf); } io_watcher_.mod_event(ctx->socket_->native_handle(), socket_event::read, 0); YASIO_KLOGI("[index: %d] open server succeed, socket.fd=%d listening at %s...", ctx->index_, (int)ctx->socket_->native_handle(), ep.to_string().c_str()); @@ -1565,6 +1570,12 @@ void io_service::do_accept_completion(io_channel* ctx) } } } +int io_service::local_address_family() const +{ + if (!yasio__testbits(ipsv_, ipsv_ipv4)) + ipsv_ = static_cast(xxsocket::getipsv()); + return ((ipsv_ & ipsv_ipv4) || !ipsv_) ? AF_INET : AF_INET6; +} transport_handle_t io_service::do_dgram_accept(io_channel* ctx, const ip::endpoint& peer, int& error) { /* @@ -1583,16 +1594,10 @@ transport_handle_t io_service::do_dgram_accept(io_channel* ctx, const ip::endpoi b. for non-win32 multicast: same with win32, because the kernel can't route same udp peer as 1 transport when the peer always sendto multicast address. */ - const bool user_route = !YASIO__UDP_KROUTE || yasio__testbits(ctx->properties_, YCPF_MCAST); - if (user_route) - { - auto it = yasio__find_if(this->transports_, [&peer](const io_transport* transport) { - using namespace std; - return yasio__testbits(transport->ctx_->properties_, YCM_UDP) && static_cast(transport)->remote_endpoint() == peer; - }); - if (it != this->transports_.end()) - return *it; - } + // both win32 and unix(like) should check does remote endpoint already assoc with a transport + auto it = this->transport_map_.find(peer); + if (it != this->transport_map_.end()) + return it->second; auto new_sock = std::make_shared(); if (new_sock->popen(peer.af(), SOCK_DGRAM)) @@ -1606,10 +1611,13 @@ transport_handle_t io_service::do_dgram_accept(io_channel* ctx, const ip::endpoi auto transport = static_cast(allocate_transport(ctx, std::move(new_sock))); // We always establish 4 tuple with clients transport->confgure_remote(peer); + const bool user_route = !YASIO__UDP_KROUTE || yasio__testbits(ctx->properties_, YCPF_MCAST); if (user_route) active_transport(transport); else handle_connect_succeed(transport); + + this->transport_map_.emplace(peer, transport); return transport; } } @@ -1640,6 +1648,13 @@ void io_service::handle_connect_succeed(transport_handle_t transport) if (options_.tcp_keepalive_.onoff) connection->set_keepalive(options_.tcp_keepalive_.onoff, options_.tcp_keepalive_.idle, options_.tcp_keepalive_.interval, options_.tcp_keepalive_.probs); } +#if !defined(_WIN32) // windows: UDP will ignore sndbuf, other: ensure sndbuf >= max_ip_mtu(65535) + if (yasio__testbits(ctx->properties_, YCM_UDP)) + { + constexpr int max_ip_mtu = static_cast((std::numeric_limits::max)()); + transport->socket_->set_optval(SOL_SOCKET, SO_SNDBUF, max_ip_mtu + 1); + } +#endif active_transport(transport); } @@ -1648,6 +1663,15 @@ void io_service::active_transport(transport_handle_t t) auto ctx = t->ctx_; auto& s = t->socket_; this->transports_.push_back(t); + if (yasio__testbits(ctx->properties_, YCM_KCP)) + { + ++this->nsched_; +#if defined(YASIO_ENABLE_KCP) + auto interval = static_cast(t)->interval(); + if (this->sched_freq_ > interval) + this->sched_freq_ = interval; +#endif + } if (!yasio__testbits(ctx->properties_, YCM_SSL)) { YASIO__UNUSED_PARAM(s); @@ -1727,12 +1751,17 @@ bool io_service::do_read(transport_handle_t transport) if (!options_.forward_packet_) { YASIO_KLOGV("[index: %d] do_read status ok, bytes transferred: %d, buffer used: %d", transport->cindex(), n, n + transport->offset_); + const int bytes_to_strip = transport->ctx_->uparams_.initial_bytes_to_strip; if (transport->expected_size_ == -1) { // decode length int length = transport->ctx_->decode_len_(transport->buffer_, transport->offset_ + n); if (length > 0) { - int bytes_to_strip = ::yasio::clamp(transport->ctx_->uparams_.initial_bytes_to_strip, 0, length - 1); + if (length < bytes_to_strip) + { + transport->set_last_errno(yasio::errc::invalid_packet, yasio::io_base::error_stage::READ); + break; + } transport->expected_size_ = length; transport->expected_packet_.reserve((std::min)(length - bytes_to_strip, YASIO_MAX_PDU_BUFFER_SIZE)); // #perfomance, avoid memory reallocte. @@ -1747,7 +1776,7 @@ bool io_service::do_read(transport_handle_t transport) } } else // process incompleted pdu - unpack(transport, transport->expected_size_ - static_cast(transport->expected_packet_.size()), n, 0); + unpack(transport, transport->expected_size_ - static_cast(transport->expected_packet_.size() + bytes_to_strip), n, 0); } else if (n > 0) { // forward packet, don't perform unpack, it's useful for implement streaming based protocol, like http, websocket and ... @@ -1763,20 +1792,21 @@ bool io_service::do_read(transport_handle_t transport) } while (false); return ret; } -void io_service::unpack(transport_handle_t transport, int bytes_expected, int bytes_transferred, int bytes_to_strip) +void io_service::unpack(transport_handle_t transport, int bytes_want /*want consume bytes from recv buffer per time*/, int bytes_transferred, + int bytes_to_strip) { auto& offset = transport->offset_; auto bytes_available = bytes_transferred + offset; auto& pkt = transport->expected_packet_; - pkt.insert(pkt.end(), transport->buffer_ + bytes_to_strip, transport->buffer_ + (std::min)(bytes_expected, bytes_available)); + pkt.insert(pkt.end(), transport->buffer_ + bytes_to_strip, transport->buffer_ + (std::min)(bytes_want, bytes_available)); // set 'offset' to bytes of remain buffer - offset = bytes_available - bytes_expected; + offset = bytes_available - bytes_want; if (offset >= 0) { /* pdu received properly */ if (offset > 0) { /* move remain data to head of buffer and hold 'offset'. */ - ::memmove(transport->buffer_, transport->buffer_ + bytes_expected, offset); + ::memmove(transport->buffer_, transport->buffer_ + bytes_want, offset); this->wait_duration_ = 0; } // move properly pdu to ready queue, the other thread who care about will retrieve it. @@ -1862,8 +1892,6 @@ bool io_service::close_internal(io_channel* ctx) } void io_service::process_timers() { - this->update_time(); - if (this->timer_queue_.empty()) return; @@ -1899,7 +1927,7 @@ void io_service::process_deferred_events() } highp_time_t io_service::get_timeout(highp_time_t usec) { - this->wait_duration_ = yasio__max_wait_usec; // Reset next wait duration per frame + this->wait_duration_ = this->sched_freq_; // Reset next wait duration per frame if (this->timer_queue_.empty()) return usec; @@ -2068,20 +2096,18 @@ void io_service::update_dns_status() } } int io_service::resolve(std::vector& endpoints, const char* hostname, unsigned short port) -{ - if (yasio__testbits(this->ipsv_, ipsv_ipv4)) - return xxsocket::resolve_v4(endpoints, hostname, port); - else if (yasio__testbits(this->ipsv_, ipsv_ipv6)) // localhost is IPv6_only network - return xxsocket::resolve_v6(endpoints, hostname, port) != 0 ? xxsocket::resolve_v4to6(endpoints, hostname, port) : 0; - return -1; +{ // prob v4, v6, v4mapped + if (xxsocket::resolve_v4(endpoints, hostname, port) == 0) + return 0; + if (xxsocket::resolve_v6(endpoints, hostname, port) == 0) + return 0; + return xxsocket::resolve_v4to6(endpoints, hostname, port); } void io_service::wakeup() { io_watcher_.wakeup(); } const char* io_service::strerror(int error) { switch (error) { - case 0: - return "No error."; case yasio::errc::resolve_host_failed: return "Resolve host failed!"; case yasio::errc::no_available_address: @@ -2187,6 +2213,11 @@ void io_service::set_option_internal(int opt, va_list ap) // lgtm [cpp/poorly-do case YOPT_S_FORWARD_PACKET: options_.forward_packet_ = !!va_arg(ap, int); break; +#if defined(_WIN32) + case YOPT_S_HRES_TIMER: + options_.hres_timer_ = !!va_arg(ap, int); + break; +#endif #if defined(YASIO_SSL_BACKEND) case YOPT_S_SSL_CERT: options_.crtfile_ = va_arg(ap, const char*); diff --git a/NativeLibs/yasio/yasio/io_service.hpp b/NativeLibs/yasio/yasio/io_service.hpp index f37c432..2277943 100644 --- a/NativeLibs/yasio/yasio/io_service.hpp +++ b/NativeLibs/yasio/yasio/io_service.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,7 @@ SOFTWARE. #include #include #include +#include #include "yasio/sz.hpp" #include "yasio/config.hpp" #include "yasio/singleton.hpp" @@ -54,7 +55,7 @@ SOFTWARE. #endif #if defined(YASIO_ENABLE_KCP) -typedef struct IKCPCB ikcpcb; +# include "ikcp.h" struct yasio_kcp_options; #endif @@ -186,6 +187,10 @@ enum // when forward packet enabled, the packet will always dispach when recv data from OS kernel immediately YOPT_S_FORWARD_PACKET, + // Set whether enable high resultion timer on win32 + // params: hres: int(0) + YOPT_S_HRES_TIMER, + // Sets channel length field based frame decode function, native C++ ONLY // params: index:int, func:decode_len_fn_t* YOPT_C_UNPACK_FN = 101, @@ -395,6 +400,11 @@ typedef highp_timer_ptr deadline_timer_ptr; typedef event_cb_t io_event_cb_t; typedef completion_cb_t io_completion_cb_t; +namespace +{ +static const int yasio__max_rcvbuf = YASIO_SZ(64, k); +} // namespace + // the ssl role enum ssl_role { @@ -770,8 +780,8 @@ class io_transport : public io_base { bool is_valid() const { return ctx_ != nullptr; } - char buffer_[YASIO_INET_BUFFER_SIZE]; // recv buffer, 64K - int offset_ = 0; // recv buffer offset + char buffer_[yasio__max_rcvbuf]; // recv buffer, 64K + int offset_ = 0; // recv buffer offset int expected_size_ = -1; sbyte_buffer expected_packet_; @@ -830,7 +840,7 @@ class YASIO_API io_transport_udp : public io_transport { YASIO__DECL void confgure_remote(const ip::endpoint& peer); // process received data from low level - YASIO__DECL virtual int handle_input(const char* data, int bytes_transferred, int& error, highp_time_t& wait_duration); + YASIO__DECL virtual int handle_input(char* data, int bytes_transferred, int& error, highp_time_t& wait_duration); ip::endpoint peer_; // for recv only, unstable mutable ip::endpoint destination_; // for sendto only, stable @@ -838,24 +848,27 @@ class YASIO_API io_transport_udp : public io_transport { }; #if defined(YASIO_ENABLE_KCP) class io_transport_kcp : public io_transport_udp { + friend class io_service; public: YASIO__DECL io_transport_kcp(io_channel* ctx, xxsocket_ptr&& s); YASIO__DECL ~io_transport_kcp(); ikcpcb* internal_object() { return kcp_; } protected: - YASIO__DECL int write(io_send_buffer&&, completion_cb_t&&) override; + YASIO__DECL void set_primitives() override; YASIO__DECL int do_read(int revent, int& error, highp_time_t& wait_duration) override; - YASIO__DECL bool do_write(highp_time_t& wait_duration) override; - YASIO__DECL int handle_input(const char* buf, int len, int& error, highp_time_t& wait_duration) override; + YASIO__DECL bool do_write(highp_time_t& wait_duration) override; - YASIO__DECL void check_timeout(highp_time_t& wait_duration) const; + YASIO__DECL int handle_input(char* buf, int len, int& error, highp_time_t& wait_duration) override; + + int interval() const { return kcp_->interval * std::milli::den; } sbyte_buffer rawbuf_; // the low level raw buffer - ikcpcb* kcp_; - std::recursive_mutex send_mtx_; + ikcpcb* kcp_{nullptr}; + IUINT32 expire_time_{0}; // the next expire time(ms) to call ikcp_update + std::function underlaying_write_cb_; }; #else class io_transport_kcp {}; @@ -1085,7 +1098,7 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields] */ int write(transport_handle_t thandle, const void* buf, size_t len, completion_cb_t completion_handler = nullptr) { - return write(thandle, sbyte_buffer{(const char*)buf, (const char*)buf + len, std::true_type{}}, std::move(completion_handler)); + return write(thandle, sbyte_buffer{(const char*)buf, (const char*)buf + len}, std::move(completion_handler)); } YASIO__DECL int write(transport_handle_t thandle, sbyte_buffer buffer, completion_cb_t completion_handler = nullptr); YASIO__DECL int forward(transport_handle_t thandle, const void* buf, size_t len, completion_cb_t completion_handler); @@ -1099,7 +1112,7 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields] */ int write_to(transport_handle_t thandle, const void* buf, size_t len, const ip::endpoint& to, completion_cb_t completion_handler = nullptr) { - return write_to(thandle, sbyte_buffer{(const char*)buf, (const char*)buf + len, std::true_type{}}, to, std::move(completion_handler)); + return write_to(thandle, sbyte_buffer{(const char*)buf, (const char*)buf + len}, to, std::move(completion_handler)); } YASIO__DECL int write_to(transport_handle_t thandle, sbyte_buffer buffer, const ip::endpoint& to, completion_cb_t completion_handler = nullptr); YASIO__DECL int forward_to(transport_handle_t thandle, const void* buf, size_t len, const ip::endpoint& to, completion_cb_t completion_handler); @@ -1221,7 +1234,7 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields] */ YASIO__DECL transport_handle_t do_dgram_accept(io_channel*, const ip::endpoint& peer, int& error); - int local_address_family() const { return ((ipsv_ & ipsv_ipv4) || !ipsv_) ? AF_INET : AF_INET6; } + YASIO__DECL int local_address_family() const; YASIO__DECL void update_dns_status(); @@ -1230,15 +1243,13 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields] /* For log macro only */ inline const print_fn2_t& __get_cprint() const { return options_.print_; } - void update_time() { this->time_ = yasio::steady_clock_t::now(); } - private: state state_ = state::UNINITIALIZED; // The service state std::thread worker_; std::thread::id worker_id_; /* The current time according to the event loop. in msecs. */ - std::chrono::time_point time_; + std::chrono::time_point current_time_; privacy::concurrent_queue events_; @@ -1249,6 +1260,7 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields] std::vector transports_; std::vector tpool_; + std::map transport_map_; // timer support timer_pair, back is earliest expire timer std::vector timer_queue_; @@ -1259,6 +1271,9 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields] io_watcher io_watcher_; + int nsched_ = 0; + int sched_freq_ = 5 * 60 * 1000 * 1000; // 5mins in us + // options struct __unnamed_options { highp_time_t connect_timeout_ = 10LL * std::micro::den; @@ -1274,6 +1289,10 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields] bool no_dispatch_ = false; // since v4.0.0 bool forward_packet_ = false; // since v3.39.8 +#if defined(_WIN32) + bool hres_timer_ = false; +#endif + // tcp keepalive settings struct __unnamed01 { int onoff = 0; @@ -1306,7 +1325,7 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields] } options_; // The ip stack version supported by localhost - u_short ipsv_ = 0; + mutable u_short ipsv_ = 0; // The stop flag to notify all transports needs close uint8_t stop_flag_ = 0; #if defined(YASIO_SSL_BACKEND) diff --git a/NativeLibs/yasio/yasio/io_watcher.hpp b/NativeLibs/yasio/yasio/io_watcher.hpp index 36a8ebc..e9f497c 100644 --- a/NativeLibs/yasio/yasio/io_watcher.hpp +++ b/NativeLibs/yasio/yasio/io_watcher.hpp @@ -4,7 +4,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// // // -// Copyright (c) 2012-2023 HALX99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) #pragma once diff --git a/NativeLibs/yasio/yasio/logging.hpp b/NativeLibs/yasio/yasio/logging.hpp index aa0fd47..bcde280 100644 --- a/NativeLibs/yasio/yasio/logging.hpp +++ b/NativeLibs/yasio/yasio/logging.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/memory.hpp b/NativeLibs/yasio/yasio/memory.hpp index d382f01..2b59a6a 100644 --- a/NativeLibs/yasio/yasio/memory.hpp +++ b/NativeLibs/yasio/yasio/memory.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/object_pool.hpp b/NativeLibs/yasio/yasio/object_pool.hpp index 0b40a7f..ebe0893 100644 --- a/NativeLibs/yasio/yasio/object_pool.hpp +++ b/NativeLibs/yasio/yasio/object_pool.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,6 +28,7 @@ SOFTWARE. #ifndef YASIO__OBJECT_POOL_HPP #define YASIO__OBJECT_POOL_HPP +#include "yasio/type_traits.hpp" #include "yasio/impl/object_pool.hpp" namespace yasio @@ -39,7 +40,7 @@ struct null_mutex { template class object_pool : public detail::object_pool { public: - object_pool(size_t _ElemCount = 128) : detail::object_pool(detail::aligned_storage_size<_Ty>::value, _ElemCount) {} + object_pool(size_t _ElemCount = 128) : detail::object_pool(::yasio::aligned_storage_size<_Ty>::value, _ElemCount) {} template _Ty* create(_Types&&... args) @@ -50,7 +51,7 @@ class object_pool : public detail::object_pool { void destroy(void* _Ptr) { ((_Ty*)_Ptr)->~_Ty(); // call the destructor - release(_Ptr); + deallocate(_Ptr); } void* allocate() diff --git a/NativeLibs/yasio/yasio/object_pool_alloc.hpp b/NativeLibs/yasio/yasio/object_pool_alloc.hpp index 3a14cbb..498bcec 100644 --- a/NativeLibs/yasio/yasio/object_pool_alloc.hpp +++ b/NativeLibs/yasio/yasio/object_pool_alloc.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/obstream.hpp b/NativeLibs/yasio/yasio/obstream.hpp index 65fa547..89f0aeb 100644 --- a/NativeLibs/yasio/yasio/obstream.hpp +++ b/NativeLibs/yasio/yasio/obstream.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -111,19 +111,12 @@ class fixed_buffer_span { ::memcpy(this->data() + offset, d, n); this->pos_ += n; } - void resize(size_t newsize) + void fill_bytes(size_t count, uint8_t val) { - if (yasio__unlikely(newsize > max_size())) + if (yasio__unlikely((count + pos_) > this->max_size())) YASIO__THROW0(std::out_of_range("fixed_buffer_span: out of range")); - this->pos_ = newsize; - } - void resize(size_t newsize, char val) - { - if (yasio__unlikely(newsize > max_size())) - YASIO__THROW0(std::out_of_range("fixed_buffer_span: out of range")); - if (this->pos_ < newsize) - ::memset(this->data() + this->pos_, val, newsize - this->pos_); - this->pos_ = newsize; + ::memset(first_ + this->pos_, val, count); + this->pos_ += count; } void reserve(size_t /*capacity*/){}; @@ -154,6 +147,7 @@ template class dynamic_buffer_span { public: using implementation_type = _Cont; + using size_type = typename _Cont::size_type; implementation_type& get_implementation() { return *this->outs_; } const implementation_type& get_implementation() const { return *this->impl_; } @@ -168,15 +162,13 @@ class dynamic_buffer_span { size_t write_bytes(size_t offset, const void* d, int n) { if ((offset + n) > outs_->size()) - outs_->resize(offset + n); + YASIO__THROW0(std::out_of_range("fixed_buffer_span: out of range")); ::memcpy(outs_->data() + offset, d, n); return n; } - - void resize(size_t newsize) { outs_->resize(newsize); } - void resize(size_t newsize, uint8_t val) { outs_->resize(newsize, val); } - void reserve(size_t capacity) { outs_->reserve(capacity); } + void fill_bytes(size_t count, uint8_t val) { outs_->insert(outs_->end(), static_cast(count), val); } + void reserve(size_t capacity) { outs_->reserve(static_cast(capacity)); } void shrink_to_fit() { outs_->shrink_to_fit(); }; void clear() { outs_->clear(); } char* data() { return outs_->data(); } @@ -190,7 +182,20 @@ class dynamic_buffer_span { template class dynamic_buffer : public dynamic_buffer_span<_Cont> { public: - dynamic_buffer() : dynamic_buffer_span<_Cont>(&impl_) {} + using super_type = dynamic_buffer_span<_Cont>; + dynamic_buffer() : super_type(&impl_) {} + dynamic_buffer(const dynamic_buffer& rhs) : super_type(&impl_), impl_(rhs.impl_) {} + dynamic_buffer(dynamic_buffer&& rhs) YASIO__NOEXCEPT : super_type(&impl_), impl_(std::move(rhs.impl_)) {} + dynamic_buffer& operator=(const dynamic_buffer& rhs) + { + impl_ = rhs.impl_; + return *this; + } + dynamic_buffer& operator=(dynamic_buffer&& rhs) YASIO__NOEXCEPT + { + impl_ = std::move(rhs.impl_); + return *this; + } private: _Cont impl_; @@ -270,7 +275,7 @@ class binary_writer_impl { auto bufsize = outs_->length(); offset_stack_.push(bufsize); - outs_->resize(bufsize + size); + fill_bytes(size); } void pop(int size) @@ -298,7 +303,7 @@ class binary_writer_impl { size_t push() { auto where = outs_->length(); - this->outs_->resize(where + sizeof(_Intty)); + this->fill_bytes(sizeof(_Intty)); return where; } template @@ -333,7 +338,7 @@ class binary_writer_impl { void write_bytes(cxx17::string_view v) { return write_bytes(v.data(), static_cast(v.size())); } void write_bytes(const void* d, int n) { outs_->write_bytes(d, n); } void write_bytes(size_t offset, const void* d, int n) { outs_->write_bytes(offset, d, n); } - void fill_bytes(int n, uint8_t val) { outs_->resize(outs_->length() + n, val); } + void fill_bytes(int n, uint8_t val = 0) { outs_->fill_bytes(n, val); } bool empty() const { return outs_->empty(); } size_t length() const { return outs_->length(); } @@ -444,13 +449,13 @@ class basic_obstream<_ConvertTraits, dynamic_extent> : public binary_writer_impl using buffer_type = typename super_type::buffer_type; basic_obstream(size_t capacity = 128) : super_type(&buffer_) { buffer_.reserve(capacity); } basic_obstream(const basic_obstream& rhs) : super_type(&buffer_), buffer_(rhs.buffer_) {} - basic_obstream(basic_obstream&& rhs) : super_type(&buffer_), buffer_(std::move(rhs.buffer_)) {} + basic_obstream(basic_obstream&& rhs) YASIO__NOEXCEPT : super_type(&buffer_), buffer_(std::move(rhs.buffer_)) {} basic_obstream& operator=(const basic_obstream& rhs) { buffer_ = rhs.buffer_; return *this; } - basic_obstream& operator=(basic_obstream&& rhs) + basic_obstream& operator=(basic_obstream&& rhs) YASIO__NOEXCEPT { buffer_ = std::move(rhs.buffer_); return *this; diff --git a/NativeLibs/yasio/yasio/platform/java/org/yasio/AppGlobals.java b/NativeLibs/yasio/yasio/platform/java/org/yasio/AppGlobals.java index 10b1691..5f52e74 100644 --- a/NativeLibs/yasio/yasio/platform/java/org/yasio/AppGlobals.java +++ b/NativeLibs/yasio/yasio/platform/java/org/yasio/AppGlobals.java @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/platform/yasio_jni.cpp b/NativeLibs/yasio/yasio/platform/yasio_jni.cpp index c298536..dfc35bb 100644 --- a/NativeLibs/yasio/yasio/platform/yasio_jni.cpp +++ b/NativeLibs/yasio/yasio/platform/yasio_jni.cpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/platform/yasio_jni.hpp b/NativeLibs/yasio/yasio/platform/yasio_jni.hpp index b7fece1..c8056e1 100644 --- a/NativeLibs/yasio/yasio/platform/yasio_jni.hpp +++ b/NativeLibs/yasio/yasio/platform/yasio_jni.hpp @@ -4,7 +4,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/NativeLibs/yasio/yasio/platform/yasio_unreal.cpp b/NativeLibs/yasio/yasio/platform/yasio_unreal.cpp index b37a655..141d8e8 100644 --- a/NativeLibs/yasio/yasio/platform/yasio_unreal.cpp +++ b/NativeLibs/yasio/yasio/platform/yasio_unreal.cpp @@ -4,7 +4,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/NativeLibs/yasio/yasio/platform/yasio_unreal.hpp b/NativeLibs/yasio/yasio/platform/yasio_unreal.hpp index 6b1a2d1..a6a3847 100644 --- a/NativeLibs/yasio/yasio/platform/yasio_unreal.hpp +++ b/NativeLibs/yasio/yasio/platform/yasio_unreal.hpp @@ -4,7 +4,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/NativeLibs/yasio/yasio/pod_vector.hpp b/NativeLibs/yasio/yasio/pod_vector.hpp new file mode 100644 index 0000000..50e0058 --- /dev/null +++ b/NativeLibs/yasio/yasio/pod_vector.hpp @@ -0,0 +1,501 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Version: 4.1.1 + +The pod_vector aka array_buffer concepts: + a. The memory model is similar to to std::vector, but only accept trivially_copyable(no destructor & no custom copy constructor) types + b. The resize behavior differrent stl, always allocate exactly + c. By default resize without fill (uninitialized and for overwrite), + use insert/append insetad if you want fill memory inside container + d. Support release internal buffer ownership with `release_pointer` + e. Transparent iterator + f. expand/append/insert/push_back will trigger memory allocate growth strategy MSVC + g. resize_and_overwrite (c++23) +*/ +#ifndef YASIO__POD_VECTOR_HPP +#define YASIO__POD_VECTOR_HPP +#include +#include +#include +#include +#include +#include "yasio/buffer_alloc.hpp" +#include "yasio/compiler/feature_test.hpp" + +namespace yasio +{ +template > +class pod_vector { +public: + using pointer = _Ty*; + using const_pointer = const _Ty*; + using reference = _Ty&; + using const_reference = const _Ty&; + using _Alloc_traits = buffer_allocator_traits<_Alloc>; + using size_type = typename _Alloc_traits::size_type; + using value_type = _Ty; + using iterator = _Ty*; // transparent iterator + using const_iterator = const _Ty*; + using allocator_type = _Alloc; + pod_vector() {} + explicit pod_vector(size_type count) { resize(static_cast(count)); } + pod_vector(size_type count, const_reference val) { resize(static_cast(count), val); } + template ::value, int> = 0> + pod_vector(_Iter first, _Iter last) + { + assign(first, last); + } + pod_vector(const pod_vector& rhs) { assign(rhs); }; + pod_vector(pod_vector&& rhs) YASIO__NOEXCEPT { assign(std::move(rhs)); } + /*pod_vector(std::initializer_list rhs) { _Assign_range(rhs.begin(), rhs.end()); }*/ + ~pod_vector() { _Tidy(); } + pod_vector& operator=(const pod_vector& rhs) + { + assign(rhs); + return *this; + } + pod_vector& operator=(pod_vector&& rhs) YASIO__NOEXCEPT + { + this->swap(rhs); + return *this; + } + template + pod_vector& operator+=(const _Cont& rhs) + { + return this->append(std::begin(rhs), std::end(rhs)); + } + pod_vector& operator+=(const_reference rhs) + { + this->push_back(rhs); + return *this; + } + template ::value, int> = 0> + void assign(_Iter first, _Iter last) + { + _Assign_range(first, last); + } + void assign(const pod_vector& rhs) { _Assign_range(rhs.begin(), rhs.end()); } + void assign(pod_vector&& rhs) { _Assign_rv(std::move(rhs)); } + void swap(pod_vector& rhs) YASIO__NOEXCEPT + { + std::swap(_Myfirst, rhs._Myfirst); + std::swap(_Mysize, rhs._Mysize); + std::swap(_Myres, rhs._Myres); + } + template ::value, int> = 0> + iterator insert(iterator pos, _Iter first, _Iter last) + { + auto mlast = _Myfirst + _Mysize; + _YASIO_VERIFY_RANGE(pos >= _Myfirst && pos <= mlast && first <= last, "pod_vector: out of range!"); + if (first != last) + { + auto insertion_off = static_cast(std::distance(_Myfirst, pos)); + if (pos == mlast) + append(first, last); + else + { + auto ifirst = std::addressof(*first); + static_assert(sizeof(*ifirst) == sizeof(value_type), "pod_vector: iterator type incompatible!"); + auto count = static_cast(std::distance(first, last)); + if (insertion_off >= 0) + { + expand(count); + pos = _Myfirst + insertion_off; + mlast = _Myfirst + _Mysize; + auto move_to = pos + count; + std::copy_n(pos, mlast - move_to, move_to); + std::copy_n((iterator)ifirst, count, pos); + } + } + return _Myfirst + insertion_off; + } + return pos; + } + iterator insert(iterator pos, size_type count, const_reference val) + { + auto mlast = _Myfirst + _Mysize; + _YASIO_VERIFY_RANGE(pos >= _Myfirst && pos <= mlast, "pod_vector: out of range!"); + if (count) + { + auto insertion_off = std::distance(_Myfirst, pos); + if (pos == mlast) + append(count, val); + else + { + if (insertion_off >= 0) + { + const auto old_size = _Mysize; + expand(count); + pos = _Myfirst + insertion_off; + mlast = _Myfirst + _Mysize; + auto move_to = pos + count; + std::copy_n(pos, mlast - move_to, move_to); + std::fill_n(pos, count, val); + } + } + return _Myfirst + insertion_off; + } + return pos; + } + iterator insert(iterator pos, const value_type& val) + { // insert val at pos + return emplace(pos, val); + } + iterator insert(iterator pos, value_type&& val) + { // insert by moving val at pos + return emplace(pos, std::move(val)); + } + template + iterator emplace(iterator pos, _Valty&&... val) + { + auto insertion_off = std::distance(_Myfirst, pos); + _YASIO_VERIFY_RANGE(insertion_off <= _Mysize, "pod_vector: out of range!"); +#if YASIO__HAS_CXX20 + emplace_back(std::forward<_Valty>(val)...); + std::rotate(begin() + insertion_off, end() - 1, end()); + return (begin() + insertion_off); +#else + auto mlast = _Myfirst + _Mysize; + if (pos == mlast) + emplace_back(std::forward<_Valty>(val)...); + else + { + if (insertion_off >= 0) + { + expand(1); + pos = _Myfirst + insertion_off; + mlast = _Myfirst + _Mysize; + auto move_to = pos + 1; + std::copy_n(pos, mlast - move_to, move_to); + ::yasio::construct_at(pos, std::forward<_Valty>(val)...); + } + } + return _Myfirst + insertion_off; +#endif + } + template ::value, int> = 0> + pod_vector& append(_Iter first, const _Iter last) + { + if (first != last) + { + auto ifirst = std::addressof(*first); + static_assert(sizeof(*ifirst) == sizeof(value_type), "pod_vector: iterator type incompatible!"); + auto count = static_cast(std::distance(first, last)); + if (count > 1) + { + const auto old_size = _Mysize; + expand(count); + std::copy_n((iterator)ifirst, count, _Myfirst + old_size); + } + else if (count == 1) + push_back(static_cast(*(iterator)ifirst)); + } + return *this; + } + pod_vector& append(size_type count, const_reference val) + { + expand(count, val); + return *this; + } + void push_back(value_type&& val) { push_back(val); } + void push_back(const value_type& val) { emplace_back(val); } + template + inline value_type& emplace_back(_Valty&&... val) + { + if (_Mysize < _Myres) + return *::yasio::construct_at(_Myfirst + _Mysize++, std::forward<_Valty>(val)...); + return *_Emplace_back_reallocate(std::forward<_Valty>(val)...); + } + iterator erase(iterator pos) + { + const auto mlast = _Myfirst + _Mysize; + _YASIO_VERIFY_RANGE(pos >= _Myfirst && pos < mlast, "pod_vector: out of range!"); + _Mysize = static_cast(std::move(pos + 1, mlast, pos) - _Myfirst); + return pos; + } + iterator erase(iterator first, iterator last) + { + const auto mlast = _Myfirst + _Mysize; + _YASIO_VERIFY_RANGE((first <= last) && first >= _Myfirst && last <= mlast, "pod_vector: out of range!"); + _Mysize = static_cast(std::move(last, mlast, first) - _Myfirst); + return first; + } + value_type& front() + { + _YASIO_VERIFY_RANGE(!empty(), "pod_vector: out of range!"); + return *_Myfirst; + } + value_type& back() + { + _YASIO_VERIFY_RANGE(!empty(), "pod_vector: out of range!"); + return _Myfirst[_Mysize - 1]; + } + static YASIO__CONSTEXPR size_type max_size() YASIO__NOEXCEPT { return _Alloc_traits::max_size(); } + iterator begin() YASIO__NOEXCEPT { return _Myfirst; } + iterator end() YASIO__NOEXCEPT { return _Myfirst + _Mysize; } + const_iterator begin() const YASIO__NOEXCEPT { return _Myfirst; } + const_iterator end() const YASIO__NOEXCEPT { return _Myfirst + _Mysize; } + pointer data() YASIO__NOEXCEPT { return _Myfirst; } + const_pointer data() const YASIO__NOEXCEPT { return _Myfirst; } + size_type capacity() const YASIO__NOEXCEPT { return _Myres; } + size_type size() const YASIO__NOEXCEPT { return _Mysize; } + size_type length() const YASIO__NOEXCEPT { return _Mysize; } + void clear() YASIO__NOEXCEPT { _Mysize = 0; } + bool empty() const YASIO__NOEXCEPT { return _Mysize == 0; } + + const_reference operator[](size_type index) const { return this->at(index); } + reference operator[](size_type index) { return this->at(index); } + const_reference at(size_type index) const + { + _YASIO_VERIFY_RANGE(index < this->size(), "pod_vector: out of range!"); + return _Myfirst[index]; + } + reference at(size_type index) + { + _YASIO_VERIFY_RANGE(index < this->size(), "pod_vector: out of range!"); + return _Myfirst[index]; + } +#pragma region modify size and capacity + void resize(size_type new_size) + { + if (this->capacity() < new_size) + _Resize_reallocate<_Reallocation_policy::_Exactly>(new_size); + else + _Eos(new_size); + } + void expand(size_type count) + { + const auto new_size = this->size() + count; + if (this->capacity() < new_size) + _Resize_reallocate<_Reallocation_policy::_At_least>(new_size); + else + _Eos(new_size); + } + void shrink_to_fit() + { // reduce capacity to size, provide strong guarantee + if (_Mysize != _Myres) + { // something to do + if (!_Mysize) + _Tidy(); + else + _Reallocate<_Reallocation_policy::_Exactly>(_Mysize); + } + } + void reserve(size_type new_cap) + { + if (this->capacity() < new_cap) + _Reallocate<_Reallocation_policy::_Exactly>(new_cap); + } + template + void resize_and_overwrite(const size_type new_size, _Operation op) + { + _Reallocate<_Reallocation_policy::_Exactly>(new_size); + _Eos(std::move(op)(_Myfirst, new_size)); + } +#pragma endregion + void resize(size_type new_size, const_reference val) + { + auto old_size = this->size(); + if (old_size != new_size) + { + resize(new_size); + if (old_size < new_size) + std::fill_n(_Myfirst + old_size, new_size - old_size, val); + } + } + void expand(size_type count, const_reference val) + { + if (count) + { + auto old_size = this->size(); + expand(count); + if (count) + std::fill_n(_Myfirst + old_size, count, val); + } + } + ptrdiff_t index_of(const_reference val) const YASIO__NOEXCEPT + { + auto it = std::find(begin(), end(), val); + if (it != this->end()) + return std::distance(begin(), it); + return -1; + } + void reset(size_type new_size) + { + resize(new_size); + memset(_Myfirst, 0x0, size_bytes()); + } + size_t size_bytes() const YASIO__NOEXCEPT { return this->size() * sizeof(value_type); } + template + pointer detach_abi(_Intty& len) YASIO__NOEXCEPT + { + len = static_cast<_Intty>(this->size()); + auto ptr = _Myfirst; + _Myfirst = nullptr; + _Mysize = _Myres = 0; + return ptr; + } + pointer detach_abi() YASIO__NOEXCEPT + { + size_type ignored_len; + return this->detach_abi(ignored_len); + } + void attach_abi(pointer ptr, size_type len) + { + _Tidy(); + _Myfirst = ptr; + _Mysize = _Myres = len; + } + pointer release_pointer() YASIO__NOEXCEPT { return detach_abi(); } + +private: + void _Eos(size_type size) YASIO__NOEXCEPT { _Mysize = size; } + template + pointer _Emplace_back_reallocate(_Valty&&... val) + { + const auto _Oldsize = _Mysize; + + if (_Oldsize == max_size()) + throw std::length_error("pod_vector too long"); + + const size_type _Newsize = _Oldsize + 1; + _Resize_reallocate<_Reallocation_policy::_At_least>(_Newsize); + const pointer _Newptr = ::yasio::construct_at(_Myfirst + _Oldsize, std::forward<_Valty>(val)...); + return _Newptr; + } + template ::value, int> = 0> + void _Assign_range(_Iter first, _Iter last) + { + auto ifirst = std::addressof(*first); + static_assert(sizeof(*ifirst) == sizeof(value_type), "pod_vector: iterator type incompatible!"); + if (ifirst != _Myfirst) + { + _Mysize = 0; + if (last > first) + { + const auto count = static_cast(std::distance(first, last)); + resize(count); + std::copy_n((iterator)ifirst, count, _Myfirst); + } + } + } + void _Assign_rv(pod_vector&& rhs) + { + memcpy(this, &rhs, sizeof(rhs)); + memset(&rhs, 0, sizeof(rhs)); + } + enum class _Reallocation_policy + { + _At_least, + _Exactly + }; + template <_Reallocation_policy _Policy> + void _Resize_reallocate(size_type size) + { + _Reallocate<_Policy>(size); + _Eos(size); + } + template <_Reallocation_policy _Policy> + void _Reallocate(size_type size) + { + size_type new_cap; + if YASIO__CONSTEXPR (_Policy == _Reallocation_policy::_Exactly) + new_cap = size; + else + new_cap = _Calculate_growth(size); + auto _Newvec = _Alloc::reallocate(_Myfirst, _Myres, new_cap); + if (_Newvec) + { + _Myfirst = _Newvec; + _Myres = new_cap; + } + else + throw std::bad_alloc{}; + } + size_type _Calculate_growth(const size_type new_size) const + { + // given _Oldcapacity and _Newsize, calculate geometric growth + const size_type old_cap = capacity(); + YASIO__CONSTEXPR auto max_cap = max_size(); + + if (old_cap > max_cap - old_cap / 2) + return max_cap; // geometric growth would overflow + + const size_type geometric = old_cap + (old_cap >> 1); + + if (geometric < new_size) + return new_size; // geometric growth would be insufficient + + return geometric; // geometric growth is sufficient + } + void _Tidy() YASIO__NOEXCEPT + { // free all storage + if (_Myfirst) + { + _Alloc::deallocate(_Myfirst, _Myres); + _Myfirst = nullptr; + _Mysize = _Myres = 0; + } + } + + pointer _Myfirst = nullptr; + size_type _Mysize = 0; + size_type _Myres = 0; +}; + +#pragma region c++20 like std::erase +template +void erase(pod_vector<_Ty, _Alloc>& cont, const _Ty& val) +{ + cont.erase(std::remove(cont.begin(), cont.end(), val), cont.end()); +} +template +void erase_if(pod_vector<_Ty, _Alloc>& cont, _Pr pred) +{ + cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end()); +} +#pragma endregion + +template +inline typename _Cont::iterator insert_sorted(_Cont& vec, typename _Cont::value_type const& val) +{ + return vec.insert(std::upper_bound(vec.begin(), vec.end(), val), val); +} + +template +inline typename _Cont::iterator insert_sorted(_Cont& vec, typename _Cont::value_type const& val, _Pred pred) +{ + return vec.insert(std::upper_bound(vec.begin(), vec.end(), val, pred), val); +} + +// alias: array_buffer +template > +using array_buffer = pod_vector<_Ty, _Alloc>; + +} // namespace yasio +#endif diff --git a/NativeLibs/yasio/yasio/ref_ptr.hpp b/NativeLibs/yasio/yasio/ref_ptr.hpp index e7d7ef7..4f07de5 100644 --- a/NativeLibs/yasio/yasio/ref_ptr.hpp +++ b/NativeLibs/yasio/yasio/ref_ptr.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/shared_mutex.hpp b/NativeLibs/yasio/yasio/shared_mutex.hpp index d316209..d35a260 100644 --- a/NativeLibs/yasio/yasio/shared_mutex.hpp +++ b/NativeLibs/yasio/yasio/shared_mutex.hpp @@ -3,7 +3,7 @@ // client application. ////////////////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2012-2023 halx99 (halx99 at live dot com) +// Copyright (c) 2012-2024 HALX99 (halx99 at live dot com) // Copyright Vicente J. Botet Escriba 2012. // Copyright Howard Hinnant 2007-2010. // diff --git a/NativeLibs/yasio/yasio/singleton.hpp b/NativeLibs/yasio/yasio/singleton.hpp index 66802ff..70b69ab 100644 --- a/NativeLibs/yasio/yasio/singleton.hpp +++ b/NativeLibs/yasio/yasio/singleton.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -50,8 +50,6 @@ SOFTWARE. #include #include -#include "yasio/config.hpp" - namespace yasio { template diff --git a/NativeLibs/yasio/yasio/ssl.hpp b/NativeLibs/yasio/yasio/ssl.hpp index 091a7fb..4f2d888 100644 --- a/NativeLibs/yasio/yasio/ssl.hpp +++ b/NativeLibs/yasio/yasio/ssl.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/strfmt.hpp b/NativeLibs/yasio/yasio/strfmt.hpp index a108820..6026c27 100644 --- a/NativeLibs/yasio/yasio/strfmt.hpp +++ b/NativeLibs/yasio/yasio/strfmt.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/string.hpp b/NativeLibs/yasio/yasio/string.hpp new file mode 100644 index 0000000..077bcb7 --- /dev/null +++ b/NativeLibs/yasio/yasio/string.hpp @@ -0,0 +1,589 @@ + +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +The yasio dedicated string (API not 100% compatible with stl) concepts: + a. no SSO, no COW, sizeof(yasio::string) = 24(x64), 12(x86) + b. The resize behavior differrent stl, always allocate exactly + c. By default resize without fill (uninitialized and for overwrite), + use insert/append insetad if you want fill memory inside container + d. Support release internal buffer ownership with `release_pointer` + e. Transparent iterator + f. The operations expand/append/insert/push_back/+= will trigger memory allocate growth strategy MSVC + g. resize_and_overwrite (c++23) + h. provide API replace_all, to_upper, to_lower which stl not provide + i. More suitable for small text file (> SSO size) read API +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "yasio/buffer_alloc.hpp" +#include "yasio/string_view.hpp" + +namespace yasio +{ +template , enable_if_t::value, int> = 0> +class basic_string { +public: + using pointer = _Elem*; + using const_pointer = const _Elem*; + using reference = _Elem&; + using const_reference = const _Elem&; + using value_type = _Elem; + using iterator = _Elem*; // transparent iterator + using const_iterator = const _Elem*; + using allocator_type = _Alloc; + using _Alloc_traits = buffer_allocator_traits<_Alloc>; + using size_type = typename _Alloc_traits::size_type; + using _Traits = std::char_traits<_Elem>; + using view_type = cxx17::basic_string_view<_Elem>; + using my_type = basic_string<_Elem, _Alloc>; + static const size_t npos = -1; + basic_string() {} + basic_string(nullptr_t) = delete; + explicit basic_string(size_type count) { resize(static_cast(count)); } + basic_string(size_type count, const_reference val) { resize(static_cast(count), val); } + template ::value, int> = 0> + basic_string(_Iter first, _Iter last) + { + assign(first, last); + } + basic_string(const basic_string& rhs) { assign(rhs); }; + basic_string(basic_string&& rhs) YASIO__NOEXCEPT { assign(std::move(rhs)); } + basic_string(view_type rhs) { assign(rhs); } + basic_string(const_pointer ntcs) { assign(ntcs); } + basic_string(const_pointer ntcs, size_type count) { assign(ntcs, ntcs + count); } + /*basic_string(std::initializer_list rhs) { _Assign_range(rhs.begin(), rhs.end()); }*/ + ~basic_string() { _Tidy(); } + operator view_type() const YASIO__NOEXCEPT { return this->view(); } + view_type view() const YASIO__NOEXCEPT { return view_type(this->c_str(), this->size()); } + basic_string& operator=(const basic_string& rhs) + { + assign(rhs); + return *this; + } + basic_string& operator=(basic_string&& rhs) YASIO__NOEXCEPT + { + this->swap(rhs); + return *this; + } + template + basic_string& operator+=(const _Cont& rhs) + { + return this->append(std::begin(rhs), std::end(rhs)); + } + basic_string& operator+=(const_reference rhs) + { + this->push_back(rhs); + return *this; + } + template ::value, int> = 0> + void assign(_Iter first, _Iter last) + { + _Assign_range(first, last); + } + void assign(view_type rhs) { _Assign_range(rhs.begin(), rhs.end()); } + void assign(const_pointer ntcs) { this->assign(ntcs, static_cast(_Traits::length(ntcs))); } + void assign(const_pointer ntcs, size_type count) { _Assign_range(ntcs, ntcs + count); } + void assign(const basic_string& rhs) { _Assign_range(rhs.begin(), rhs.end()); } + void assign(basic_string&& rhs) { _Assign_rv(std::move(rhs)); } + void swap(basic_string& rhs) YASIO__NOEXCEPT + { + std::swap(_Myfirst, rhs._Myfirst); + std::swap(_Mysize, rhs._Mysize); + std::swap(_Myres, rhs._Myres); + } + template ::value, int> = 0> + iterator insert(iterator _Where, _Iter first, _Iter last) + { + auto _Mylast = _Myfirst + _Mysize; + _YASIO_VERIFY_RANGE(_Where >= _Myfirst && _Where <= _Mylast && first <= last, "basic_string: out of range!"); + if (first != last) + { + auto insertion_pos = static_cast(std::distance(_Myfirst, _Where)); + if (_Where == _Mylast) + append(first, last); + else + { + auto ifirst = std::addressof(*first); + static_assert(sizeof(*ifirst) == sizeof(value_type), "basic_string: iterator type incompatible!"); + auto count = static_cast(std::distance(first, last)); + if (insertion_pos >= 0) + { + auto old_size = _Mylast - _Myfirst; + expand(count); + _Where = _Myfirst + insertion_pos; + _Mylast = _Myfirst + _Mysize; + auto move_to = _Where + count; + std::copy_n(_Where, _Mylast - move_to, move_to); + std::copy_n((iterator)ifirst, count, _Where); + } + } + return _Myfirst + insertion_pos; + } + return _Where; + } + iterator insert(iterator _Where, size_type count, const_reference val) + { + auto _Mylast = _Myfirst + _Mysize; + _YASIO_VERIFY_RANGE(_Where >= _Myfirst && _Where <= _Mylast, "basic_string: out of range!"); + if (count) + { + auto insertion_pos = std::distance(_Myfirst, _Where); + if (_Where == _Mylast) + append(count, val); + else + { + if (insertion_pos >= 0) + { + const auto old_size = _Mysize; + expand(count); + _Where = _Myfirst + insertion_pos; + _Mylast = _Myfirst + _Mysize; + auto move_to = _Where + count; + std::copy_n(_Where, _Mylast - move_to, move_to); + std::fill_n(_Where, count, val); + } + } + return _Myfirst + insertion_pos; + } + return _Where; + } + basic_string& append(view_type value) { return this->append(value.begin(), value.end()); } + template ::value, int> = 0> + basic_string& append(_Iter first, const _Iter last) + { + if (first != last) + { + auto ifirst = std::addressof(*first); + static_assert(sizeof(*ifirst) == sizeof(value_type), "basic_string: iterator type incompatible!"); + auto count = static_cast(std::distance(first, last)); + if (count > 1) + { + const auto old_size = _Mysize; + expand(count); + std::copy_n((iterator)ifirst, count, _Myfirst + old_size); + } + else if (count == 1) + push_back(static_cast(*(iterator)ifirst)); + } + return *this; + } + basic_string& append(size_type count, const_reference val) + { + expand(count, val); + return *this; + } + void push_back(value_type&& v) { push_back(v); } + void push_back(const value_type& v) + { + expand(1); + back() = v; + } + iterator erase(iterator _Where) + { + const auto _Mylast = _Myfirst + _Mysize; + _YASIO_VERIFY_RANGE(_Where >= _Myfirst && _Where < _Mylast, "basic_string: out of range!"); + _Mysize = static_cast(std::move(_Where + 1, _Mylast, _Where) - _Myfirst); + return _Where; + } + iterator erase(iterator first, iterator last) + { + const auto _Mylast = _Myfirst + _Mysize; + _YASIO_VERIFY_RANGE((first <= last) && first >= _Myfirst && last <= _Mylast, "basic_string: out of range!"); + _Mysize = static_cast(std::move(last, _Mylast, first) - _Myfirst); + return first; + } + value_type& front() + { + _YASIO_VERIFY_RANGE(!empty(), "basic_string: out of range!"); + return *_Myfirst; + } + value_type& back() + { + _YASIO_VERIFY_RANGE(!empty(), "basic_string: out of range!"); + return _Myfirst[_Mysize - 1]; + } + static YASIO__CONSTEXPR size_type max_size() YASIO__NOEXCEPT { return _Alloc_traits::max_size(); } + +#pragma region Iterators + iterator begin() YASIO__NOEXCEPT { return this->data(); } + iterator end() YASIO__NOEXCEPT { return begin() + _Mysize; } + const_iterator begin() const YASIO__NOEXCEPT { return this->data(); } + const_iterator end() const YASIO__NOEXCEPT { return begin() + _Mysize; } +#pragma endregion + + pointer data() YASIO__NOEXCEPT { return _Myfirst ? _Myfirst : reinterpret_cast(&_Myfirst); } + const_pointer data() const YASIO__NOEXCEPT { return _Myfirst ? _Myfirst : reinterpret_cast(&_Myfirst); } + const_pointer c_str() const YASIO__NOEXCEPT { return this->data(); } + const_reference operator[](size_type index) const { return this->at(index); } + reference operator[](size_type index) { return this->at(index); } + const_reference at(size_type index) const + { + _YASIO_VERIFY_RANGE(index < this->size(), "basic_string: out of range!"); + return _Myfirst[index]; + } + reference at(size_type index) + { + _YASIO_VERIFY_RANGE(index < this->size(), "basic_string: out of range!"); + return _Myfirst[index]; + } + +#pragma region Capacity + size_type capacity() const YASIO__NOEXCEPT { return _Myres; } + size_type size() const YASIO__NOEXCEPT { return _Mysize; } + size_type length() const YASIO__NOEXCEPT { return _Mysize; } + void clear() YASIO__NOEXCEPT { _Mysize = 0; } + bool empty() const YASIO__NOEXCEPT { return _Mysize == 0; } + void resize(size_type new_size) + { + if (this->capacity() < new_size) + _Resize_reallocate<_Reallocation_policy::_Exactly>(new_size); + else + _Eos(new_size); + } + void expand(size_type count) + { + const auto new_size = this->size() + count; + if (this->capacity() < new_size) + _Resize_reallocate<_Reallocation_policy::_At_least>(new_size); + else + _Eos(new_size); + } + void shrink_to_fit() + { // reduce capacity to size, provide strong guarantee + if (_Mysize != _Myres) + { // something to do + if (!_Mysize) + _Tidy(); + else + _Reallocate<_Reallocation_policy::_Exactly>(_Mysize); + } + } + void reserve(size_type new_cap) + { + if (this->capacity() < new_cap) + _Reallocate<_Reallocation_policy::_Exactly>(new_cap); + } + template + void resize_and_overwrite(const size_type _New_size, _Operation _Op) + { + _Reallocate<_Reallocation_policy::_Exactly>(_New_size); + _Eos(std::move(_Op)(_Myfirst, _New_size)); + } +#pragma endregion + void resize(size_type new_size, const_reference val) + { + auto old_size = this->size(); + if (old_size != new_size) + { + resize(new_size); + if (old_size < new_size) + std::fill_n(_Myfirst + old_size, new_size - old_size, val); + } + } + void expand(size_type count, const_reference val) + { + if (count) + { + auto old_size = this->size(); + expand(count); + if (count) + std::fill_n(_Myfirst + old_size, count, val); + } + } + template + pointer detach_abi(_Intty& len) YASIO__NOEXCEPT + { + len = static_cast<_Intty>(this->size()); + auto ptr = _Myfirst; + _Myfirst = nullptr; + _Mysize = _Myres = 0; + return ptr; + } + pointer detach_abi() YASIO__NOEXCEPT + { + size_type ignored_len; + return this->detach_abi(ignored_len); + } + void attach_abi(pointer ptr, size_type len) + { + _Tidy(); + _Myfirst = ptr; + _Mysize = _Myres = len; + } + pointer release_pointer() YASIO__NOEXCEPT { return detach_abi(); } + +#pragma region find stubs, String operations + size_t find(value_type c, size_t pos = 0) const YASIO__NOEXCEPT { return view().find(c, pos); } + size_t find(view_type str, size_t pos = 0) const YASIO__NOEXCEPT { return view().find(str, pos); } + + size_t rfind(value_type c, size_t pos = npos) const YASIO__NOEXCEPT { return view().rfind(c, pos); } + size_t rfind(view_type str, size_t pos = npos) const YASIO__NOEXCEPT { return view().rfind(str, pos); } + + size_t find_first_of(value_type c, size_t pos = 0) const YASIO__NOEXCEPT { return view().find_first_of(c, pos); } + size_t find_first_of(view_type str, size_t pos = 0) const YASIO__NOEXCEPT { return view().find_first_of(str, pos); } + + size_t find_last_of(value_type c, size_t pos = npos) const YASIO__NOEXCEPT { return view().find_last_of(c, pos); } + size_t find_last_of(view_type str, size_t pos = npos) const YASIO__NOEXCEPT { return view().find_last_of(str, pos); } + + size_t find_first_not_of(value_type c, size_t pos = 0) const YASIO__NOEXCEPT { return view().find_first_not_of(c, pos); } + size_t find_first_not_of(view_type str, size_t pos = 0) const YASIO__NOEXCEPT { return view().find_first_not_of(str, pos); } + + int compare(view_type str) const YASIO__NOEXCEPT { return view().compare(str); } + + my_type substr(size_t pos = 0, size_t len = npos) const { return my_type{view().substr(pos, len)}; } + + my_type& replace(const size_type _Off, size_type _Nx, view_type value) { return this->replace(_Off, _Nx, value.data(), value.length()); } + my_type& replace(const size_type _Off, size_type _Nx, const _Elem* const _Ptr, const size_type _Count) + { // replace port from https://github.com/microsoft/stl + _YASIO_VERIFY_RANGE(_Off < _Mysize, "basic_string: out of range!"); + _Nx = (std::min)(_Nx, _Mysize - _Off); + if (_Nx == _Count) + { // size doesn't change, so a single move does the trick + _Traits::move(_Myfirst + _Off, _Ptr, _Count); + return *this; + } + + const size_type _Old_size = _Mysize; + const size_type _Suffix_size = _Old_size - _Nx - _Off + 1; + if (_Count < _Nx) + { // suffix shifts backwards; we don't have to move anything out of the way + _Elem* const _Old_ptr = _Myfirst; + _Elem* const _Insert_at = _Old_ptr + _Off; + _Traits::move(_Insert_at, _Ptr, _Count); + _Traits::move(_Insert_at + _Count, _Insert_at + _Nx, _Suffix_size); + + const auto _New_size = _Old_size - (_Nx - _Count); + // _ASAN_STRING_MODIFY(*this, _Old_size, _New_size); + _Mysize = _New_size; + return *this; + } + + const size_type _Growth = static_cast(_Count - _Nx); + + // checking for overlapping ranges is technically UB (considering string literals), so just always reallocate + // and copy to the new buffer if constant evaluated +#if YASIO__HAS_CXX20 + if (!std::is_constant_evaluated()) +#endif // _HAS_CXX20 + { + if (_Growth <= _Myres - _Old_size) + { // growth fits + _Mysize = _Old_size + _Growth; + _Elem* const _Old_ptr = _Myfirst; + _Elem* const _Insert_at = _Old_ptr + _Off; + _Elem* const _Suffix_at = _Insert_at + _Nx; + + size_type _Ptr_shifted_after; // see rationale in insert + if (_Ptr + _Count <= _Insert_at || _Ptr > _Old_ptr + _Old_size) + { + _Ptr_shifted_after = _Count; + } + else if (_Suffix_at <= _Ptr) + { + _Ptr_shifted_after = 0; + } + else + { + _Ptr_shifted_after = static_cast(_Suffix_at - _Ptr); + } + + _Traits::move(_Suffix_at + _Growth, _Suffix_at, _Suffix_size); + // next case must be move, in case _Ptr begins before _Insert_at and contains part of the hole; + // this case doesn't occur in insert because the new content must come from outside the removed + // content there (because in insert there is no removed content) + _Traits::move(_Insert_at, _Ptr, _Ptr_shifted_after); + // the next case can be copy, because it comes from the chunk moved out of the way in the + // first move, and the hole we're filling can't alias the chunk we moved out of the way + _Traits::copy(_Insert_at + _Ptr_shifted_after, _Ptr + _Growth + _Ptr_shifted_after, _Count - _Ptr_shifted_after); + return *this; + } + } + + return _Reallocate_grow_by( + _Growth, + [](_Elem* const _New_ptr, const size_type _Old_size, const size_type _Off, const size_type _Nx, const _Elem* const _Ptr, const size_type _Count) { + _Traits::copy(_New_ptr + _Off + _Count, _New_ptr + _Off + _Nx, _Old_size - _Nx - _Off + 1); + _Traits::copy(_New_ptr + _Off, _Ptr, _Count); + }, + _Off, _Nx, _Ptr, _Count); + } + template + my_type& _Reallocate_grow_by(const size_type _Size_increase, _Fty _Fn, _ArgTys... _Args) + { + const size_type _Old_size = _Mysize; + if (max_size() - _Old_size < _Size_increase) + throw std::length_error("string too long"); + + const size_type _New_size = _Old_size + _Size_increase; + const size_type _Old_capacity = _Myres; + const size_type _New_capacity = _Calculate_growth(_New_size); + pointer _New_ptr = _Alloc::reallocate(_Myfirst, _Myres, _New_capacity + 1); // throws + + _Mysize = _New_size; + _Myres = _New_capacity; + + const pointer _Old_ptr = _Myfirst; + _Fn(_New_ptr, _Old_size, _Args...); + _Myfirst = _New_ptr; + + return *this; + } +#pragma endregion + +#pragma region replace all stubs, yasio string spec + size_t replace_all(view_type from, view_type to) + { + if (from == to) + return 0; + int hints = 0; + size_t pos = 0; + const size_t predicate = !from.empty() ? 0 : 1; + while ((pos = this->find(from, pos)) != my_type::npos) + { + (void)this->replace(pos, from.length(), to); + pos += (to.length() + predicate); + ++hints; + } + return hints; + } + void replace_all(value_type from, value_type to) YASIO__NOEXCEPT { std::replace(this->begin(), this->end(), from, to); } +#pragma endregion + +#pragma region to_lower, to_upper + my_type& to_lower() YASIO__NOEXCEPT + { + std::transform(this->begin(), this->end(), this->begin(), ::tolower); + return *this; + } + my_type& to_upper() YASIO__NOEXCEPT + { + std::transform(this->begin(), this->end(), this->begin(), ::toupper); + return *this; + } +#pragma endregion + +private: + void _Eos(size_type size) YASIO__NOEXCEPT + { + _Mysize = size; + _Myfirst[_Mysize] = static_cast(0); + } + template ::value, int> = 0> + void _Assign_range(_Iter first, _Iter last) + { + auto ifirst = std::addressof(*first); + static_assert(sizeof(*ifirst) == sizeof(value_type), "basic_string: iterator type incompatible!"); + if (ifirst != _Myfirst) + { + _Mysize = 0; + if (last > first) + { + const auto count = static_cast(std::distance(first, last)); + resize(count); + std::copy_n((iterator)ifirst, count, _Myfirst); + } + } + } + void _Assign_rv(basic_string&& rhs) + { + memcpy(this, &rhs, sizeof(rhs)); + memset(&rhs, 0, sizeof(rhs)); + } + enum class _Reallocation_policy + { + _At_least, + _Exactly + }; + template <_Reallocation_policy _Policy> + void _Resize_reallocate(size_type size) + { + _Reallocate<_Policy>(size); + _Eos(size); + } + template <_Reallocation_policy _Policy> + void _Reallocate(size_type size) + { + size_type new_cap; + if YASIO__CONSTEXPR (_Policy == _Reallocation_policy::_Exactly) + new_cap = size + 1; + else + new_cap = (std::max)(_Calculate_growth(size), size + 1); + auto _Newvec = _Alloc::reallocate(_Myfirst, _Myres, new_cap); + if (_Newvec) + { + _Myfirst = _Newvec; + _Myres = new_cap; + } + else + throw std::bad_alloc{}; + } + size_type _Calculate_growth(const size_type _Newsize) const + { + // given _Oldcapacity and _Newsize, calculate geometric growth + const size_type _Oldcapacity = capacity(); + YASIO__CONSTEXPR auto _Max = max_size(); + + if (_Oldcapacity > _Max - _Oldcapacity / 2) + return _Max; // geometric growth would overflow + + const size_type _Geometric = _Oldcapacity + (_Oldcapacity >> 1); + + if (_Geometric < _Newsize) + return _Newsize; // geometric growth would be insufficient + + return _Geometric; // geometric growth is sufficient + } + void _Tidy() YASIO__NOEXCEPT + { // free all storage + if (_Myfirst) + { + _Alloc::deallocate(_Myfirst, _Myres); + _Myfirst = nullptr; + _Mysize = _Myres = 0; + } + } + + pointer _Myfirst = nullptr; + size_type _Mysize = 0; + size_type _Myres = 0; +}; +using string = basic_string; +#if defined(__cpp_lib_char8_t) +using u8string = basic_string; +#endif +using wstring = basic_string; +using u16string = basic_string; +using u32string = basic_string; +} // namespace yasio diff --git a/NativeLibs/yasio/yasio/string_view.hpp b/NativeLibs/yasio/yasio/string_view.hpp index 350e4d1..6e7116c 100644 --- a/NativeLibs/yasio/yasio/string_view.hpp +++ b/NativeLibs/yasio/yasio/string_view.hpp @@ -1,11 +1,11 @@ ////////////////////////////////////////////////////////////////////////////////////////// -// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any // client application. ////////////////////////////////////////////////////////////////////////////////////////// /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Copyright (c) 2016 Matthew Rodusek(matthew.rodusek@gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy @@ -33,6 +33,7 @@ See: https://github.com/bitwizeshift/string_view-standalone #include #include #include +#include "yasio/impl/char_traits.hpp" #include "yasio/compiler/feature_test.hpp" /// wcsncasecmp workaround for android API level < 23, copy from msvc ucrt 10.0.18362.0 'wcsnicmp' @@ -73,272 +74,6 @@ inline int wcsncasecmp(wchar_t const* const lhs, wchar_t const* const rhs, size_ # include namespace cxx17 { -template -inline size_t __xxtraits_find(const typename _Traits::char_type* _Haystack, const size_t _Hay_size, - const size_t _Start_at, const typename _Traits::char_type* _Needle, - const size_t _Needle_size) -{ // search [_Haystack, _Haystack + - // _Hay_size) for [_Needle, _Needle + - // _Needle_size), at/after _Start_at - if (_Needle_size > _Hay_size || _Start_at > _Hay_size - _Needle_size) - { // xpos cannot exist, report failure - // N4659 24.3.2.7.2 [string.find]/1 says: - // 1. _Start_at <= xpos - // 2. xpos + _Needle_size <= _Hay_size; - // therefore: - // 3. _Needle_size <= _Hay_size (by 2) - // (checked above) - // 4. _Start_at + _Needle_size <= - // _Hay_size (substitute 1 into 2) - // 5. _Start_at <= _Hay_size - - // _Needle_size (4, move _Needle_size to - // other side) (also checked above) - return static_cast(-1); - } - - if (_Needle_size == 0) - { // empty string always matches if xpos is possible - return _Start_at; - } - - const auto _Possible_matches_end = _Haystack + (_Hay_size - _Needle_size) + 1; - for (auto _Match_try = _Haystack + _Start_at;; ++_Match_try) - { - _Match_try = _Traits::find(_Match_try, static_cast(_Possible_matches_end - _Match_try), - *_Needle); - if (!_Match_try) - { // didn't find first character; report failure - return static_cast(-1); - } - - if (_Traits::compare(_Match_try, _Needle, _Needle_size) == 0) - { // found match - return static_cast(_Match_try - _Haystack); - } - } -} - -template -inline size_t __xxtraits_find_ch(const typename _Traits::char_type* _Haystack, - const size_t _Hay_size, const size_t _Start_at, - const typename _Traits::char_type _Ch) -{ // search [_Haystack, _Haystack + _Hay_size) - // for _Ch, at/after _Start_at - if (_Start_at < _Hay_size) - { - const auto _Found_at = _Traits::find(_Haystack + _Start_at, _Hay_size - _Start_at, _Ch); - if (_Found_at) - { - return static_cast(_Found_at - _Haystack); - } - } - - return static_cast(-1); // (npos) no match -} - -template -inline size_t __xxtraits_rfind(const typename _Traits::char_type* _Haystack, const size_t _Hay_size, - const size_t _Start_at, const typename _Traits::char_type* _Needle, - const size_t _Needle_size) -{ // search [_Haystack, _Haystack + _Hay_size) - // for [_Needle, _Needle + _Needle_size) - // beginning before _Start_at - if (_Needle_size == 0) - { - return (std::min)(_Start_at, _Hay_size); // empty string always matches - } - - if (_Needle_size <= _Hay_size) - { // room for match, look for it - for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - _Needle_size);; - --_Match_try) - { - if (_Traits::eq(*_Match_try, *_Needle) && - _Traits::compare(_Match_try, _Needle, _Needle_size) == 0) - { - return static_cast(_Match_try - _Haystack); // found a match - } - - if (_Match_try == _Haystack) - { - break; // at beginning, no more chance for match - } - } - } - - return static_cast(-1); // no match -} - -template -inline size_t __xxtraits_rfind_ch(const typename _Traits::char_type* _Haystack, - const size_t _Hay_size, const size_t _Start_at, - const typename _Traits::char_type _Ch) -{ // search [_Haystack, _Haystack + - // _Hay_size) for _Ch before _Start_at - if (_Hay_size != 0) - { // room for match, look for it - for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - 1);; --_Match_try) - { - if (_Traits::eq(*_Match_try, _Ch)) - { - return static_cast(_Match_try - _Haystack); // found a match - } - - if (_Match_try == _Haystack) - { - break; // at beginning, no more chance for match - } - } - } - - return static_cast(-1); // no match -} - -template -inline size_t __xxtraits_find_last_of(const typename _Traits::char_type* _Haystack, - const size_t _Hay_size, const size_t _Start_at, - const typename _Traits::char_type* _Needle, - const size_t _Needle_size) -{ // in [_Haystack, _Haystack + _Hay_size), look for - // last of [_Needle, _Needle + _Needle_size), before - // _Start_at general algorithm - if (_Needle_size != 0 && _Hay_size != 0) - { // worth searching, do it - for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - 1);; --_Match_try) - { - if (_Traits::find(_Needle, _Needle_size, *_Match_try)) - { - return static_cast(_Match_try - _Haystack); // found a match - } - - if (_Match_try == _Haystack) - { - break; // at beginning, no more chance for match - } - } - } - - return static_cast(-1); // no match -} - -template -inline size_t _xxtraits_find_last_not_of(const typename _Traits::char_type* _Haystack, - const size_t _Hay_size, const size_t _Start_at, - const typename _Traits::char_type* _Needle, - const size_t _Needle_size) -{ // in [_Haystack, _Haystack + _Hay_size), look for - // none of [_Needle, _Needle + _Needle_size), before - // _Start_at general algorithm - if (_Hay_size != 0) - { // worth searching, do it - for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - 1);; --_Match_try) - { - if (!_Traits::find(_Needle, _Needle_size, *_Match_try)) - { - return static_cast(_Match_try - _Haystack); // found a match - } - - if (_Match_try == _Haystack) - { - break; // at beginning, no more chance for match - } - } - } - - return static_cast(-1); // no match -} - -template -inline size_t __xxtraits_find_first_of(const typename _Traits::char_type* _Haystack, - const size_t _Hay_size, const size_t _Start_at, - const typename _Traits::char_type* _Needle, - const size_t _Needle_size) -{ // in [_Haystack, _Haystack + _Hay_size), look for - // one of [_Needle, _Needle + _Needle_size), at/after - // _Start_at general algorithm - if (_Needle_size != 0 && _Start_at < _Hay_size) - { // room for match, look for it - const auto _End = _Haystack + _Hay_size; - for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) - { - if (_Traits::find(_Needle, _Needle_size, *_Match_try)) - { - return (static_cast(_Match_try - _Haystack)); // found a match - } - } - } - - return (static_cast(-1)); // no match -} - -template -inline size_t __xxtraits_find_first_not_of(const typename _Traits::char_type* _Haystack, - const size_t _Hay_size, const size_t _Start_at, - const typename _Traits::char_type* _Needle, - const size_t _Needle_size) -{ // in [_Haystack, _Haystack + _Hay_size), look for none - // of [_Needle, _Needle + _Needle_size), at/after - // _Start_at general algorithm - if (_Start_at < _Hay_size) - { // room for match, look for it - const auto _End = _Haystack + _Hay_size; - for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) - { - if (!_Traits::find(_Needle, _Needle_size, *_Match_try)) - { - return (static_cast(_Match_try - _Haystack)); // found a match - } - } - } - - return (static_cast(-1)); // no match -} - -template -inline size_t __xxtraits_find_not_ch(const typename _Traits::char_type* _Haystack, - const size_t _Hay_size, const size_t _Start_at, - const typename _Traits::char_type _Ch) -{ // search [_Haystack, _Haystack + _Hay_size) for any value other - // than _Ch, at/after _Start_at - if (_Start_at < _Hay_size) - { // room for match, look for it - const auto _End = _Haystack + _Hay_size; - for (auto _Match_try = _Haystack + _Start_at; _Match_try < _End; ++_Match_try) - { - if (!_Traits::eq(*_Match_try, _Ch)) - { - return (static_cast(_Match_try - _Haystack)); // found a match - } - } - } - - return (static_cast(-1)); // no match -} - -template -inline size_t __xxtraits_rfind_not_ch(const typename _Traits::char_type* _Haystack, - const size_t _Hay_size, const size_t _Start_at, - const typename _Traits::char_type _Ch) -{ // search [_Haystack, _Haystack + _Hay_size) for any value other than _Ch before _Start_at - if (_Hay_size != 0) - { // room for match, look for it - for (auto _Match_try = _Haystack + (std::min)(_Start_at, _Hay_size - 1);; --_Match_try) - { - if (!_Traits::eq(*_Match_try, _Ch)) - { - return (static_cast(_Match_try - _Haystack)); // found a match - } - - if (_Match_try == _Haystack) - { - break; // at beginning, no more chance for match - } - } - } - - return (static_cast(-1)); // no match -} - //////////////////////////////////////////////////////////////////////////// /// \brief A wrapper around non-owned strings. /// @@ -346,10 +81,11 @@ inline size_t __xxtraits_rfind_not_ch(const typename _Traits::char_type* _Haysta /// /// \ingroup core //////////////////////////////////////////////////////////////////////////// -template > class basic_string_view; +template > +class basic_string_view; -template class basic_string_view -{ +template +class basic_string_view { //------------------------------------------------------------------------ // Public Member Types //------------------------------------------------------------------------ @@ -558,8 +294,7 @@ template class basic_string_view /// \return negative value if this view is less than the other character /// sequence, zero if the both character sequences are equal, positive /// value if this view is greater than the other character sequence. - int compare(size_type pos1, size_type count1, basic_string_view v, size_type pos2, - size_type count2) const; + int compare(size_type pos1, size_type count1, basic_string_view v, size_type pos2, size_type count2) const; /// \brief Compares two character sequences /// @@ -683,6 +418,9 @@ template class basic_string_view //-------------------------------------------------------------------------- using string_view = basic_string_view; +# if defined(__cpp_lib_char8_t) +using u8string_view = basic_string_view; +# endif using wstring_view = basic_string_view; using u16string_view = basic_string_view; using u32string_view = basic_string_view; @@ -701,19 +439,15 @@ inline basic_string_view<_CharT, _Traits>::basic_string_view() : m_str(nullptr), template template -inline basic_string_view<_CharT, _Traits>::basic_string_view( - const std::basic_string<_CharT, _Traits, Allocator>& str) - : m_str(str.c_str()), m_size(str.size()) +inline basic_string_view<_CharT, _Traits>::basic_string_view(const std::basic_string<_CharT, _Traits, Allocator>& str) : m_str(str.c_str()), m_size(str.size()) {} template -inline basic_string_view<_CharT, _Traits>::basic_string_view(const char_type* str) - : m_str(str), m_size(traits_type::length(str)) +inline basic_string_view<_CharT, _Traits>::basic_string_view(const char_type* str) : m_str(str), m_size(traits_type::length(str)) {} template -inline basic_string_view<_CharT, _Traits>::basic_string_view(const char_type* str, size_type count) - : m_str(str), m_size(count) +inline basic_string_view<_CharT, _Traits>::basic_string_view(const char_type* str, size_type count) : m_str(str), m_size(count) {} //-------------------------------------------------------------------------- @@ -721,22 +455,19 @@ inline basic_string_view<_CharT, _Traits>::basic_string_view(const char_type* st //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::size() const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::size() const { return m_size; } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::length() const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::length() const { return size(); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::max_size() const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::max_size() const { return npos - 1; } @@ -752,29 +483,25 @@ inline bool basic_string_view<_CharT, _Traits>::empty() const //-------------------------------------------------------------------------- template -inline const typename basic_string_view<_CharT, _Traits>::char_type* -basic_string_view<_CharT, _Traits>::c_str() const +inline const typename basic_string_view<_CharT, _Traits>::char_type* basic_string_view<_CharT, _Traits>::c_str() const { return m_str; } template -inline const typename basic_string_view<_CharT, _Traits>::char_type* -basic_string_view<_CharT, _Traits>::data() const +inline const typename basic_string_view<_CharT, _Traits>::char_type* basic_string_view<_CharT, _Traits>::data() const { return m_str; } template -inline typename basic_string_view<_CharT, _Traits>::const_reference -basic_string_view<_CharT, _Traits>::operator[](size_t pos) const +inline typename basic_string_view<_CharT, _Traits>::const_reference basic_string_view<_CharT, _Traits>::operator[](size_t pos) const { return m_str[pos]; } template -inline typename basic_string_view<_CharT, _Traits>::const_reference -basic_string_view<_CharT, _Traits>::at(size_t pos) const +inline typename basic_string_view<_CharT, _Traits>::const_reference basic_string_view<_CharT, _Traits>::at(size_t pos) const { if (yasio__unlikely(pos >= m_size)) YASIO__THROW(std::out_of_range("Input out of range in basic_string_view::at"), 0); @@ -782,15 +509,13 @@ basic_string_view<_CharT, _Traits>::at(size_t pos) const } template -inline typename basic_string_view<_CharT, _Traits>::const_reference -basic_string_view<_CharT, _Traits>::front() const +inline typename basic_string_view<_CharT, _Traits>::const_reference basic_string_view<_CharT, _Traits>::front() const { return *m_str; } template -inline typename basic_string_view<_CharT, _Traits>::const_reference -basic_string_view<_CharT, _Traits>::back() const +inline typename basic_string_view<_CharT, _Traits>::const_reference basic_string_view<_CharT, _Traits>::back() const { return m_str[m_size - 1]; } @@ -825,16 +550,14 @@ inline void basic_string_view<_CharT, _Traits>::swap(basic_string_view& v) template template -inline std::basic_string<_CharT, _Traits, Allocator> -basic_string_view<_CharT, _Traits>::to_string(const Allocator& a) const +inline std::basic_string<_CharT, _Traits, Allocator> basic_string_view<_CharT, _Traits>::to_string(const Allocator& a) const { return std::basic_string<_CharT, _Traits, Allocator>(m_str, m_size, a); } template template -inline basic_string_view<_CharT, _Traits>::operator std::basic_string<_CharT, _Traits, Allocator>() - const +inline basic_string_view<_CharT, _Traits>::operator std::basic_string<_CharT, _Traits, Allocator>() const { return std::basic_string<_CharT, _Traits, Allocator>(m_str, m_size); } @@ -844,8 +567,7 @@ inline basic_string_view<_CharT, _Traits>::operator std::basic_string<_CharT, _T //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::copy(char_type* dest, size_type count, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::copy(char_type* dest, size_type count, size_type pos) const { if (yasio__unlikely(pos >= m_size)) YASIO__THROW(std::out_of_range("Index out of range in basic_string_view::copy"), 0); @@ -856,8 +578,7 @@ basic_string_view<_CharT, _Traits>::copy(char_type* dest, size_type count, size_ } template -inline basic_string_view<_CharT, _Traits> -basic_string_view<_CharT, _Traits>::substr(size_t pos, size_t len) const +inline basic_string_view<_CharT, _Traits> basic_string_view<_CharT, _Traits>::substr(size_t pos, size_t len) const { const size_type max_length = pos > m_size ? 0 : m_size - pos; if (yasio__unlikely(pos >= m_size)) @@ -877,16 +598,13 @@ inline int basic_string_view<_CharT, _Traits>::compare(basic_string_view v) cons } template -inline int basic_string_view<_CharT, _Traits>::compare(size_type pos, size_type count, - basic_string_view v) const +inline int basic_string_view<_CharT, _Traits>::compare(size_type pos, size_type count, basic_string_view v) const { return substr(pos, count).compare(v); } template -inline int basic_string_view<_CharT, _Traits>::compare(size_type pos1, size_type count1, - basic_string_view v, size_type pos2, - size_type count2) const +inline int basic_string_view<_CharT, _Traits>::compare(size_type pos1, size_type count1, basic_string_view v, size_type pos2, size_type count2) const { return substr(pos1, count1).compare(v.substr(pos2, count2)); } @@ -898,15 +616,13 @@ inline int basic_string_view<_CharT, _Traits>::compare(const char_type* s) const } template -inline int basic_string_view<_CharT, _Traits>::compare(size_type pos, size_type count, - const char_type* s) const +inline int basic_string_view<_CharT, _Traits>::compare(size_type pos, size_type count, const char_type* s) const { return substr(pos, count).compare(basic_string_view<_CharT, _Traits>(s)); } template -inline int basic_string_view<_CharT, _Traits>::compare(size_type pos, size_type count1, - const char_type* s, size_type count2) const +inline int basic_string_view<_CharT, _Traits>::compare(size_type pos, size_type count1, const char_type* s, size_type count2) const { return substr(pos, count1).compare(basic_string_view<_CharT, _Traits>(s, count2)); } @@ -914,29 +630,25 @@ inline int basic_string_view<_CharT, _Traits>::compare(size_type pos, size_type //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find(basic_string_view v, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find(basic_string_view v, size_type pos) const { return __xxtraits_find<_Traits>(m_str, m_size, pos, v.m_str, v.m_size); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find(char_type c, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find(char_type c, size_type pos) const { return find(basic_string_view<_CharT, _Traits>(&c, 1), pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find(const char_type* s, size_type pos, size_type count) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find(const char_type* s, size_type pos, size_type count) const { return find(basic_string_view<_CharT, _Traits>(s, count), pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find(const char_type* s, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find(const char_type* s, size_type pos) const { return find(basic_string_view<_CharT, _Traits>(s), pos); } @@ -944,29 +656,26 @@ basic_string_view<_CharT, _Traits>::find(const char_type* s, size_type pos) cons //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::rfind(basic_string_view v, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::rfind(basic_string_view v, size_type pos) const { return __xxtraits_rfind<_Traits>(m_str, m_size, pos, v.m_str, v.m_size); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::rfind(char_type c, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::rfind(char_type c, size_type pos) const { return rfind(basic_string_view<_CharT, _Traits>(&c, 1), pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::rfind(const char_type* s, size_type pos, size_type count) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::rfind(const char_type* s, size_type pos, + size_type count) const { return rfind(basic_string_view<_CharT, _Traits>(s, count), pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::rfind(const char_type* s, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::rfind(const char_type* s, size_type pos) const { return rfind(basic_string_view<_CharT, _Traits>(s), pos); } @@ -974,30 +683,26 @@ basic_string_view<_CharT, _Traits>::rfind(const char_type* s, size_type pos) con //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_first_of(basic_string_view v, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_first_of(basic_string_view v, size_type pos) const { return __xxtraits_find_first_of<_Traits>(m_str, m_size, pos, v.m_str, v.m_size); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_first_of(char_type c, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_first_of(char_type c, size_type pos) const { return __xxtraits_find_ch<_Traits>(m_str, m_size, pos, c); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_first_of(const char_type* s, size_type pos, - size_type count) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_first_of(const char_type* s, size_type pos, + size_type count) const { return find_first_of(basic_string_view<_CharT, _Traits>(s, count), pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_first_of(const char_type* s, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_first_of(const char_type* s, size_type pos) const { return find_first_of(basic_string_view<_CharT, _Traits>(s), pos); } @@ -1005,30 +710,26 @@ basic_string_view<_CharT, _Traits>::find_first_of(const char_type* s, size_type //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_last_of(basic_string_view v, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_last_of(basic_string_view v, size_type pos) const { return __xxtraits_find_last_of<_Traits>(m_str, m_size, pos, v.m_str, v.m_size); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_last_of(char_type c, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_last_of(char_type c, size_type pos) const { return __xxtraits_rfind_ch<_Traits>(m_str, m_size, pos, c); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_last_of(const char_type* s, size_type pos, - size_type count) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_last_of(const char_type* s, size_type pos, + size_type count) const { return find_last_of(basic_string_view<_CharT, _Traits>(s, count), pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_last_of(const char_type* s, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_last_of(const char_type* s, size_type pos) const { return find_last_of(basic_string_view<_CharT, _Traits>(s), pos); } @@ -1036,30 +737,26 @@ basic_string_view<_CharT, _Traits>::find_last_of(const char_type* s, size_type p //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_first_not_of(basic_string_view v, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_first_not_of(basic_string_view v, size_type pos) const { return __xxtraits_find_first_not_of<_Traits>(m_str, m_size, pos, v.m_str, v.m_size, pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_first_not_of(char_type c, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_first_not_of(char_type c, size_type pos) const { return __xxtraits_find_not_ch<_Traits>(m_str, m_size, pos, c); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_first_not_of(const char_type* s, size_type pos, - size_type count) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_first_not_of(const char_type* s, size_type pos, + size_type count) const { return find_first_not_of(basic_string_view<_CharT, _Traits>(s, count), pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_first_not_of(const char_type* s, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_first_not_of(const char_type* s, size_type pos) const { return find_first_not_of(basic_string_view<_CharT, _Traits>(s), pos); } @@ -1067,30 +764,26 @@ basic_string_view<_CharT, _Traits>::find_first_not_of(const char_type* s, size_t //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_last_not_of(basic_string_view v, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_last_not_of(basic_string_view v, size_type pos) const { - return _xxtraits_find_last_not_of(m_str, m_size, pos, v.m_str, v.m_size); + return __xxtraits_find_last_not_of<_Traits>(m_str, m_size, pos, v.m_str, v.m_size); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_last_not_of(char_type c, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_last_not_of(char_type c, size_type pos) const { return __xxtraits_rfind_not_ch<_Traits>(m_str, m_size, pos, c); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_last_not_of(const char_type* s, size_type pos, - size_type count) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_last_not_of(const char_type* s, size_type pos, + size_type count) const { return find_last_not_of(basic_string_view<_CharT, _Traits>(s, count), pos); } template -inline typename basic_string_view<_CharT, _Traits>::size_type -basic_string_view<_CharT, _Traits>::find_last_not_of(const char_type* s, size_type pos) const +inline typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>::find_last_not_of(const char_type* s, size_type pos) const { return find_last_not_of(basic_string_view<_CharT, _Traits>(s), pos); } @@ -1100,29 +793,25 @@ basic_string_view<_CharT, _Traits>::find_last_not_of(const char_type* s, size_ty //-------------------------------------------------------------------------- template -inline typename basic_string_view<_CharT, _Traits>::const_iterator -basic_string_view<_CharT, _Traits>::begin() const +inline typename basic_string_view<_CharT, _Traits>::const_iterator basic_string_view<_CharT, _Traits>::begin() const { return m_str; } template -inline typename basic_string_view<_CharT, _Traits>::const_iterator -basic_string_view<_CharT, _Traits>::end() const +inline typename basic_string_view<_CharT, _Traits>::const_iterator basic_string_view<_CharT, _Traits>::end() const { return m_str + m_size; } template -inline typename basic_string_view<_CharT, _Traits>::const_iterator -basic_string_view<_CharT, _Traits>::cbegin() const +inline typename basic_string_view<_CharT, _Traits>::const_iterator basic_string_view<_CharT, _Traits>::cbegin() const { return m_str; } template -inline typename basic_string_view<_CharT, _Traits>::const_iterator -basic_string_view<_CharT, _Traits>::cend() const +inline typename basic_string_view<_CharT, _Traits>::const_iterator basic_string_view<_CharT, _Traits>::cend() const { return m_str + m_size; } @@ -1132,8 +821,7 @@ basic_string_view<_CharT, _Traits>::cend() const //-------------------------------------------------------------------------- template -std::basic_ostream<_CharT, _Traits>& operator<<(std::basic_ostream<_CharT, _Traits>& o, - const basic_string_view<_CharT, _Traits>& str) +std::basic_ostream<_CharT, _Traits>& operator<<(std::basic_ostream<_CharT, _Traits>& o, const basic_string_view<_CharT, _Traits>& str) { o.write(str.data(), str.size()); return o; @@ -1150,8 +838,7 @@ inline void swap(basic_string_view<_CharT, _Traits>& lhs, basic_string_view<_Cha //-------------------------------------------------------------------------- template -inline bool operator==(const basic_string_view<_CharT, _Traits>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator==(const basic_string_view<_CharT, _Traits>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return lhs.compare(rhs) == 0; } @@ -1169,15 +856,13 @@ inline bool operator==(const _CharT* lhs, const basic_string_view<_CharT, _Trait } template -inline bool operator==(const std::basic_string<_CharT, _Traits, Allocator>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator==(const std::basic_string<_CharT, _Traits, Allocator>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return basic_string_view<_CharT, _Traits>(lhs) == rhs; } template -inline bool operator==(const basic_string_view<_CharT, _Traits>& lhs, - const std::basic_string<_CharT, _Traits, Allocator>& rhs) +inline bool operator==(const basic_string_view<_CharT, _Traits>& lhs, const std::basic_string<_CharT, _Traits, Allocator>& rhs) { return lhs == basic_string_view<_CharT, _Traits>(rhs); } @@ -1185,8 +870,7 @@ inline bool operator==(const basic_string_view<_CharT, _Traits>& lhs, //-------------------------------------------------------------------------- template -inline bool operator!=(const basic_string_view<_CharT, _Traits>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator!=(const basic_string_view<_CharT, _Traits>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return lhs.compare(rhs) != 0; } @@ -1204,23 +888,20 @@ inline bool operator!=(const _CharT* lhs, const basic_string_view<_CharT, _Trait } template -inline bool operator!=(const std::basic_string<_CharT, _Traits, Allocator>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator!=(const std::basic_string<_CharT, _Traits, Allocator>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return basic_string_view<_CharT, _Traits>(lhs) != rhs; } template -inline bool operator!=(const basic_string_view<_CharT, _Traits>& lhs, - const std::basic_string<_CharT, _Traits, Allocator>& rhs) +inline bool operator!=(const basic_string_view<_CharT, _Traits>& lhs, const std::basic_string<_CharT, _Traits, Allocator>& rhs) { return lhs != basic_string_view<_CharT, _Traits>(rhs); } //-------------------------------------------------------------------------- template -inline bool operator<(const basic_string_view<_CharT, _Traits>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator<(const basic_string_view<_CharT, _Traits>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return lhs.compare(rhs) < 0; } @@ -1238,15 +919,13 @@ inline bool operator<(const _CharT* lhs, const basic_string_view<_CharT, _Traits } template -inline bool operator<(const std::basic_string<_CharT, _Traits, Allocator>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator<(const std::basic_string<_CharT, _Traits, Allocator>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return basic_string_view<_CharT, _Traits>(lhs) < rhs; } template -inline bool operator<(const basic_string_view<_CharT, _Traits>& lhs, - const std::basic_string<_CharT, _Traits, Allocator>& rhs) +inline bool operator<(const basic_string_view<_CharT, _Traits>& lhs, const std::basic_string<_CharT, _Traits, Allocator>& rhs) { return lhs < basic_string_view<_CharT, _Traits>(rhs); } @@ -1254,8 +933,7 @@ inline bool operator<(const basic_string_view<_CharT, _Traits>& lhs, //-------------------------------------------------------------------------- template -inline bool operator>(const basic_string_view<_CharT, _Traits>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator>(const basic_string_view<_CharT, _Traits>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return lhs.compare(rhs) > 0; } @@ -1273,15 +951,13 @@ inline bool operator>(const _CharT* lhs, const basic_string_view<_CharT, _Traits } template -inline bool operator>(const std::basic_string<_CharT, _Traits, Allocator>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator>(const std::basic_string<_CharT, _Traits, Allocator>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return basic_string_view<_CharT, _Traits>(lhs) > rhs; } template -inline bool operator>(const basic_string_view<_CharT, _Traits>& lhs, - const std::basic_string<_CharT, _Traits, Allocator>& rhs) +inline bool operator>(const basic_string_view<_CharT, _Traits>& lhs, const std::basic_string<_CharT, _Traits, Allocator>& rhs) { return lhs > basic_string_view<_CharT, _Traits>(rhs); } @@ -1289,8 +965,7 @@ inline bool operator>(const basic_string_view<_CharT, _Traits>& lhs, //-------------------------------------------------------------------------- template -inline bool operator<=(const basic_string_view<_CharT, _Traits>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator<=(const basic_string_view<_CharT, _Traits>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return lhs.compare(rhs) <= 0; } @@ -1308,15 +983,13 @@ inline bool operator<=(const _CharT* lhs, const basic_string_view<_CharT, _Trait } template -inline bool operator<=(const std::basic_string<_CharT, _Traits, Allocator>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator<=(const std::basic_string<_CharT, _Traits, Allocator>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return basic_string_view<_CharT, _Traits>(lhs) <= rhs; } template -inline bool operator<=(const basic_string_view<_CharT, _Traits>& lhs, - const std::basic_string<_CharT, _Traits, Allocator>& rhs) +inline bool operator<=(const basic_string_view<_CharT, _Traits>& lhs, const std::basic_string<_CharT, _Traits, Allocator>& rhs) { return lhs <= basic_string_view<_CharT, _Traits>(rhs); } @@ -1324,8 +997,7 @@ inline bool operator<=(const basic_string_view<_CharT, _Traits>& lhs, //-------------------------------------------------------------------------- template -inline bool operator>=(const basic_string_view<_CharT, _Traits>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator>=(const basic_string_view<_CharT, _Traits>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return lhs.compare(rhs) >= 0; } @@ -1343,26 +1015,24 @@ inline bool operator>=(const _CharT* lhs, const basic_string_view<_CharT, _Trait } template -inline bool operator>=(const std::basic_string<_CharT, _Traits, Allocator>& lhs, - const basic_string_view<_CharT, _Traits>& rhs) +inline bool operator>=(const std::basic_string<_CharT, _Traits, Allocator>& lhs, const basic_string_view<_CharT, _Traits>& rhs) { return basic_string_view<_CharT, _Traits>(lhs) >= rhs; } template -inline bool operator>=(const basic_string_view<_CharT, _Traits>& lhs, - const std::basic_string<_CharT, _Traits, Allocator>& rhs) +inline bool operator>=(const basic_string_view<_CharT, _Traits>& lhs, const std::basic_string<_CharT, _Traits, Allocator>& rhs) { return lhs >= basic_string_view<_CharT, _Traits>(rhs); } //----------------------------------------------------------------- // FNV1a hash from msvc++ # if YASIO__64BITS -static YASIO__CONSTEXPR size_t _FNV_offset_basis = 14695981039346656037ULL; -static YASIO__CONSTEXPR size_t _FNV_prime = 1099511628211ULL; +static const size_t _FNV_offset_basis = 14695981039346656037ULL; +static const size_t _FNV_prime = 1099511628211ULL; # else /* defined(_M_X64), etc. */ -static YASIO__CONSTEXPR size_t _FNV_offset_basis = 2166136261U; -static YASIO__CONSTEXPR size_t _FNV_prime = 16777619U; +static const size_t _FNV_offset_basis = 2166136261U; +static const size_t _FNV_prime = 16777619U; # endif /* defined(_M_X64), etc. */ inline size_t _FNV1a_hash(const void* _First, size_t _Count) { // FNV-1a hash function for bytes in [_First, _First+_Count) @@ -1378,8 +1048,8 @@ inline size_t _FNV1a_hash(const void* _First, size_t _Count) } // namespace cxx17 namespace std { -template struct hash> -{ // hash functor for basic_string_view +template +struct hash> { // hash functor for basic_string_view typedef cxx17::basic_string_view<_Elem> _Kty; size_t operator()(const _Kty& _Keyval) const @@ -1404,22 +1074,10 @@ inline namespace literals { inline namespace string_view_literals { -inline cxx17::string_view operator"" _sv(const char* _Str, size_t _Len) -{ - return cxx17::string_view(_Str, _Len); -} -inline cxx17::wstring_view operator"" _sv(const wchar_t* _Str, size_t _Len) -{ - return cxx17::wstring_view(_Str, _Len); -} -inline cxx17::u16string_view operator"" _sv(const char16_t* _Str, size_t _Len) -{ - return cxx17::u16string_view(_Str, _Len); -} -inline cxx17::u32string_view operator"" _sv(const char32_t* _Str, size_t _Len) -{ - return cxx17::u32string_view(_Str, _Len); -} +inline cxx17::string_view operator"" _sv(const char* _Str, size_t _Len) { return cxx17::string_view(_Str, _Len); } +inline cxx17::wstring_view operator"" _sv(const wchar_t* _Str, size_t _Len) { return cxx17::wstring_view(_Str, _Len); } +inline cxx17::u16string_view operator"" _sv(const char16_t* _Str, size_t _Len) { return cxx17::u16string_view(_Str, _Len); } +inline cxx17::u32string_view operator"" _sv(const char32_t* _Str, size_t _Len) { return cxx17::u32string_view(_Str, _Len); } } // namespace string_view_literals } // namespace literals } // namespace cxx17 @@ -1448,28 +1106,31 @@ inline std::basic_string<_CharT, _Traits, Allocator>& append(std::basic_string<_ template > inline std::basic_string<_CharT, _Traits, Allocator> svtos(const basic_string_view<_CharT, _Traits>& value) { - using string_type = std::basic_string<_CharT, _Traits, Allocator>; - return !value.empty() ? string_type(value.data(), value.size()) : string_type{}; + using string_type = std::basic_string<_CharT, _Traits, Allocator>; + return !value.empty() ? string_type(value.data(), value.size()) : string_type{}; } } // namespace cxx17 namespace cxx20 { -template< class T > +template using decay_t = typename std::decay::type; -template< class T > +template using remove_const_t = typename std::remove_const::type; namespace char_ranges { // allow get char type from char*, wchar_t*, std::string, std::wstring -template struct value_type { +template +struct value_type { using type = typename _Ty::value_type; }; -template struct value_type<_Ty&> { +template +struct value_type<_Ty&> { using type = remove_const_t<_Ty>; }; -template struct value_type<_Ty*> { +template +struct value_type<_Ty*> { using type = remove_const_t<_Ty>; }; } // namespace char_ranges @@ -1482,20 +1143,20 @@ inline bool starts_with(cxx17::basic_string_view<_CharT> lhs, return lhs.size() >= v.size() && lhs.compare(0, v.size(), v) == 0; } -template +template inline bool starts_with(_T1&& lhs, _T2&& v) // (2) { using char_type = typename char_ranges::value_type>::type; return starts_with(cxx17::basic_string_view{lhs}, cxx17::basic_string_view{v}); } -template +template inline bool starts_with(cxx17::basic_string_view<_CharT> lhs, int c) // (3) { return !lhs.empty() && lhs.front() == c; } -template +template inline bool starts_with(_Ty&& lhs, int c) // (4) { using char_type = typename char_ranges::value_type>::type; @@ -1511,7 +1172,7 @@ inline bool ends_with(cxx17::basic_string_view<_CharT> lhs, return lhs.size() >= v.size() && lhs.compare(offset, v.size(), v) == 0; } -template +template inline bool ends_with(_T1&& lhs, _T2&& v) // (2) { using char_type = typename char_ranges::value_type>::type; @@ -1524,7 +1185,8 @@ inline bool ends_with(cxx17::basic_string_view<_CharT> lhs, int c) // (3) return !lhs.empty() && lhs.back() == c; } -template inline bool ends_with(_Ty&& lhs, int c) // (4) +template +inline bool ends_with(_Ty&& lhs, int c) // (4) { using char_type = typename char_ranges::value_type>::type; return ends_with(cxx17::basic_string_view{lhs}, c); @@ -1542,8 +1204,7 @@ inline bool iequals(cxx17::basic_string_view lhs, cxx17::basic_strin return lhs.size() == v.size() && ::_strnicmp(lhs.data(), v.data(), v.size()) == 0; } template <> -inline bool iequals(cxx17::basic_string_view lhs, - cxx17::basic_string_view v) +inline bool iequals(cxx17::basic_string_view lhs, cxx17::basic_string_view v) { return lhs.size() == v.size() && ::_wcsnicmp(lhs.data(), v.data(), v.size()) == 0; } @@ -1554,13 +1215,13 @@ inline bool iequals(cxx17::basic_string_view lhs, cxx17::basic_strin return lhs.size() == v.size() && ::strncasecmp(lhs.data(), v.data(), v.size()) == 0; } template <> -inline bool iequals(cxx17::basic_string_view lhs, - cxx17::basic_string_view v) +inline bool iequals(cxx17::basic_string_view lhs, cxx17::basic_string_view v) { return lhs.size() == v.size() && ::wcsncasecmp(lhs.data(), v.data(), v.size()) == 0; } #endif -template inline bool iequals(_T1&& lhs, _T2&& v) +template +inline bool iequals(_T1&& lhs, _T2&& v) { using char_type = typename char_ranges::value_type>::type; return iequals(cxx17::basic_string_view{lhs}, cxx17::basic_string_view{v}); @@ -1573,7 +1234,8 @@ inline bool starts_with(cxx17::basic_string_view<_CharT> lhs, return lhs.size() >= v.size() && iequals(lhs.substr(0, v.size()), v); } -template inline bool starts_with(_T1&& lhs, _T2&& v) // (2) +template +inline bool starts_with(_T1&& lhs, _T2&& v) // (2) { using char_type = typename char_ranges::value_type>::type; return starts_with(cxx17::basic_string_view{lhs}, cxx17::basic_string_view{v}); @@ -1585,7 +1247,8 @@ inline bool starts_with(cxx17::basic_string_view<_CharT> lhs, int c) // (3) return !lhs.empty() && ::tolower(lhs.front()) == ::tolower(c); } -template inline bool starts_with(_Ty&& lhs, int c) // (4) +template +inline bool starts_with(_Ty&& lhs, int c) // (4) { using char_type = typename char_ranges::value_type>::type; return starts_with(cxx17::basic_string_view{lhs}, c); @@ -1599,7 +1262,8 @@ inline bool ends_with(cxx17::basic_string_view<_CharT> lhs, return lhs.size() >= v.size() && iequals(lhs.substr(lhs.size() - v.size(), lhs.npos), v); } -template inline bool ends_with(_T1&& lhs, _T2&& v) // (2) +template +inline bool ends_with(_T1&& lhs, _T2&& v) // (2) { using char_type = typename char_ranges::value_type>::type; return ends_with(cxx17::basic_string_view{lhs}, cxx17::basic_string_view{v}); @@ -1611,7 +1275,8 @@ inline bool ends_with(cxx17::basic_string_view<_CharT> lhs, int c) // (3) return !lhs.empty() && ::tolower(lhs.back()) == ::tolower(c); } -template inline bool ends_with(_Ty&& lhs, int c) // (4) +template +inline bool ends_with(_Ty&& lhs, int c) // (4) { using char_type = typename char_ranges::value_type>::type; return ends_with(cxx17::basic_string_view{lhs}, c); diff --git a/NativeLibs/yasio/yasio/sz.hpp b/NativeLibs/yasio/yasio/sz.hpp index e1af72d..fdade5e 100644 --- a/NativeLibs/yasio/yasio/sz.hpp +++ b/NativeLibs/yasio/yasio/sz.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/thread_name.hpp b/NativeLibs/yasio/yasio/thread_name.hpp index 1919e26..2d62adf 100644 --- a/NativeLibs/yasio/yasio/thread_name.hpp +++ b/NativeLibs/yasio/yasio/thread_name.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/type_traits.hpp b/NativeLibs/yasio/yasio/type_traits.hpp new file mode 100644 index 0000000..7774ce6 --- /dev/null +++ b/NativeLibs/yasio/yasio/type_traits.hpp @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once +#include + +namespace yasio +{ +template +struct aligned_storage_size { + static const size_t value = sizeof(typename std::aligned_storage::type); +}; +template +struct is_aligned_storage { + static const bool value = aligned_storage_size<_Ty>::value == sizeof(_Ty); +}; +template +struct is_iterator : public std::integral_constant::value> {}; + +template +using enable_if_t = typename ::std::enable_if<_Test, _Ty>::type; + +template +struct is_byte_type { + static const bool value = std::is_same<_Ty, char>::value || std::is_same<_Ty, unsigned char>::value; +}; + +template +struct is_char_type { + static const bool value = std::is_integral<_Ty>::value && sizeof(_Ty) <= sizeof(char32_t); +}; + +} // namespace yasio diff --git a/NativeLibs/yasio/yasio/utils.hpp b/NativeLibs/yasio/yasio/utils.hpp index 25f3561..b85d7c3 100644 --- a/NativeLibs/yasio/yasio/utils.hpp +++ b/NativeLibs/yasio/yasio/utils.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/wtimer_hres.hpp b/NativeLibs/yasio/yasio/wtimer_hres.hpp new file mode 100644 index 0000000..57f0d65 --- /dev/null +++ b/NativeLibs/yasio/yasio/wtimer_hres.hpp @@ -0,0 +1,105 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// A multi-platform support c++11 library with focus on asynchronous socket I/O for any +// client application. +////////////////////////////////////////////////////////////////////////////////////////// +/* +The MIT License (MIT) + +Copyright (c) 2012-2024 HALX99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +#ifdef _WIN32 + +# include "yasio/config.hpp" +# include "yasio/utils.hpp" + +# if defined(YASIO__USE_TIMEAPI) +# include +# pragma comment(lib, "Winmm.lib") +# endif + +namespace yasio +{ +/** +* CLASS wtimer_hres: The windows timer high-resolution setup helper +*/ +struct wtimer_hres { + using NTSTATUS = LONG; + /** + * @param res the timer resolution in 100-ns units: 100-ns * 10000 = 1ms + * @remark + * - timeapi timeBeginPeriod max resolution is 1ms + * - ZwSetTimerResolution max resolution is 0.5ms aka 100-ns * 5000 + */ + static const ULONG _1ms_den = 10000; + wtimer_hres(ULONG timer_res = _1ms_den) + { +# if defined(YASIO__USE_TIMEAPI) + TIMECAPS tc; + if (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(TIMECAPS))) + { + timer_res_ = yasio::clamp(static_cast(timer_res / _1ms_den), tc.wPeriodMin, tc.wPeriodMax); + timeBeginPeriod(timer_res_); + } +# else + do + { + HMODULE hNtDll = GetModuleHandleW(L"ntdll"); + if (!hNtDll) + break; + + NTSTATUS(__stdcall * NtQueryTimerResolution) + (OUT PULONG MinimumResolution, OUT PULONG MaximumResolution, OUT PULONG CurrentResolution) = + reinterpret_cast(GetProcAddress(hNtDll, "NtQueryTimerResolution")); + if (!NtQueryTimerResolution) + break; + ZwSetTimerResolution = reinterpret_cast(GetProcAddress(hNtDll, "ZwSetTimerResolution")); + if (!ZwSetTimerResolution) + break; + + ULONG MinimumResolution, MaximumResolution, CurrentResolution; + if (NtQueryTimerResolution(&MinimumResolution, &MaximumResolution, &CurrentResolution) != 0) + break; + ZwSetTimerResolution(yasio::clamp(timer_res, MaximumResolution, MinimumResolution), TRUE, &timer_res); + } while (false); +# endif + } + ~wtimer_hres() + { +# if defined(YASIO__USE_TIMEAPI) + if (timer_res_ != 0) + timeEndPeriod(timer_res_); +# else + if (timer_res_) + ZwSetTimerResolution(timer_res_, FALSE, nullptr); +# endif + } +# if defined(YASIO__USE_TIMEAPI) + UINT timer_res_{0}; +# else + NTSTATUS(__stdcall* ZwSetTimerResolution) + (IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution){nullptr}; + ULONG timer_res_{0}; +# endif +}; + +} // namespace yasio +#endif diff --git a/NativeLibs/yasio/yasio/xxsocket.cpp b/NativeLibs/yasio/yasio/xxsocket.cpp index 40dbc5f..87c8894 100644 --- a/NativeLibs/yasio/yasio/xxsocket.cpp +++ b/NativeLibs/yasio/yasio/xxsocket.cpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -76,12 +76,14 @@ namespace compat } // namespace yasio #endif +#define YASIO_NO_ERROR "No error." +#define YASIO_NO_ERROR_SZ (sizeof(YASIO_NO_ERROR)) + namespace yasio { YASIO__NS_INLINE namespace inet { - int xxsocket::xpconnect(const char* hostname, u_short port, u_short local_port) { auto flags = getipsv(); @@ -976,28 +978,37 @@ bool xxsocket::not_recv_error(int error) { return (error == EWOULDBLOCK || error const char* xxsocket::strerror(int error) { + if (error != 0) + { #if defined(_WIN32) - static char error_msg[256]; - return xxsocket::strerror_r(error, error_msg, sizeof(error_msg)); + static char error_msg[256]; + return xxsocket::strerror_r(error, error_msg, sizeof(error_msg)); #else - return ::strerror(error); + return ::strerror(error); #endif + } + return YASIO_NO_ERROR; } const char* xxsocket::strerror_r(int error, char* buf, size_t buflen) { + if (error != 0) + { #if defined(_WIN32) - ZeroMemory(buf, buflen); - ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK /* remove line-end charactors \r\n */, NULL, - error, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), // english language - buf, static_cast(buflen), nullptr); + ZeroMemory(buf, buflen); + ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK /* remove line-end charactors \r\n */, NULL, + error, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), // english language + buf, static_cast(buflen), nullptr); - return buf; + return buf; #else - // XSI-compliant return int not const char*, refer to: https://linux.die.net/man/3/strerror_r - auto YASIO__UNUSED ret = ::strerror_r(error, buf, buflen); - return buf; + // XSI-compliant return int not const char*, refer to: https://linux.die.net/man/3/strerror_r + auto YASIO__UNUSED ret = ::strerror_r(error, buf, buflen); + return buf; #endif + } + strncpy(buf, YASIO_NO_ERROR, (std::min)(YASIO_NO_ERROR_SZ, buflen)); + return buf; } const char* xxsocket::gai_strerror(int error) diff --git a/NativeLibs/yasio/yasio/xxsocket.hpp b/NativeLibs/yasio/yasio/xxsocket.hpp index 2af1189..0d7ae51 100644 --- a/NativeLibs/yasio/yasio/xxsocket.hpp +++ b/NativeLibs/yasio/yasio/xxsocket.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -40,6 +40,7 @@ SOFTWARE. #include #include "yasio/impl/socket.hpp" #include "yasio/logging.hpp" +#include "yasio/string_view.hpp" namespace yasio { @@ -218,6 +219,17 @@ struct endpoint final { explicit operator bool() const { return this->af() != AF_UNSPEC; } + friend bool operator<(const endpoint& lhs, const endpoint& rhs) + { // apply operator < to operands + if (lhs.af() == AF_INET) + return (static_cast(lhs.in4_.sin_addr.s_addr) + lhs.in4_.sin_port) < (static_cast(rhs.in4_.sin_addr.s_addr) + rhs.in4_.sin_port); + return ::memcmp(&lhs, &rhs, sizeof(rhs)) < 0; + } + friend bool operator==(const endpoint& lhs, const endpoint& rhs) + { // apply operator == to operands + return !(lhs < rhs) && !(rhs < lhs); + } + endpoint& operator=(const endpoint& rhs) { return as_is(rhs); } endpoint& as_is(const endpoint& rhs) { @@ -542,7 +554,7 @@ struct endpoint final { auto offst = s.find(fmt); if (offst != std::string::npos) { - snprintf(snum,sizeof(snum), "%u", addr_bytes[idx]); + snprintf(snum, sizeof(snum), "%u", addr_bytes[idx]); s.replace(offst, _N0, snum); } } @@ -1136,17 +1148,14 @@ using namespace yasio::inet; } // namespace yasio namespace std -{ // VS2013 the operator must be at namespace std -inline bool operator<(const yasio::inet::ip::endpoint& lhs, const yasio::inet::ip::endpoint& rhs) -{ // apply operator < to operands - if (lhs.af() == AF_INET) - return (static_cast(lhs.in4_.sin_addr.s_addr) + lhs.in4_.sin_port) < (static_cast(rhs.in4_.sin_addr.s_addr) + rhs.in4_.sin_port); - return ::memcmp(&lhs, &rhs, sizeof(rhs)) < 0; -} -inline bool operator==(const yasio::inet::ip::endpoint& lhs, const yasio::inet::ip::endpoint& rhs) -{ // apply operator == to operands - return !(lhs < rhs) && !(rhs < lhs); -} +{ +template <> +struct hash { + std::size_t operator()(const yasio::ip::endpoint& ep) const YASIO__NOEXCEPT + { + return std::hash()(cxx17::string_view{reinterpret_cast(&ep), static_cast(ep.len())}); + } +}; } // namespace std #if defined(YASIO_HEADER_ONLY) diff --git a/NativeLibs/yasio/yasio/yasio.hpp b/NativeLibs/yasio/yasio/yasio.hpp index f1ade48..6146adb 100644 --- a/NativeLibs/yasio/yasio/yasio.hpp +++ b/NativeLibs/yasio/yasio/yasio.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NativeLibs/yasio/yasio/yasio.natvis b/NativeLibs/yasio/yasio/yasio.natvis index 1dd52f9..e49aba7 100644 --- a/NativeLibs/yasio/yasio/yasio.natvis +++ b/NativeLibs/yasio/yasio/yasio.natvis @@ -1,25 +1,83 @@ - - {{ size={_Mylast - _Myfirst} {_Myfirst,[_Mylast - _Myfirst]s8} }} + + + {{ size={_Mysize} capacity={_Myres} }} - _Mylast - _Myfirst - _Myend - _Myfirst + _Mysize + _Myres - _Mylast - _Myfirst + _Mysize _Myfirst - - {{ size={_Mylast - _Myfirst} capacity={_Myend - _Myfirst} }} + + {{ size={_Mysize} {_Myfirst,[_Mysize]s8} }} - _Mylast - _Myfirst - _Myend - _Myfirst + _Mysize + _Myres - _Mylast - _Myfirst + _Mysize + _Myfirst + + + + + + {_Myfirst,s8} + {&_Myfirst,s8} + _Myfirst,s8 + &_Myfirst,s8 + + _Mysize + _Myres + + _Mysize + _Myfirst + + + _Mysize + &_Myfirst + + + + + + + {_Myfirst,su} + {&_Myfirst,su} + _Myfirst,su + &_Myfirst,su + + _Mysize + _Myres + + _Mysize _Myfirst + + _Mysize + &_Myfirst + + + + + {_Myfirst,s32} + {&_Myfirst,s32} + _Myfirst,s32 + &_Myfirst,s32 + + _Mysize + _Myres + + _Mysize + _Myfirst + + + _Mysize + &_Myfirst + diff --git a/NativeLibs/yasio/yasio/yasio_fwd.hpp b/NativeLibs/yasio/yasio/yasio_fwd.hpp index c40cd8f..e709670 100644 --- a/NativeLibs/yasio/yasio/yasio_fwd.hpp +++ b/NativeLibs/yasio/yasio/yasio_fwd.hpp @@ -5,7 +5,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2023 HALX99 +Copyright (c) 2012-2024 HALX99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Packages/manifest.json b/Packages/manifest.json index 0a7f915..27a4f85 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,6 +1,5 @@ { "dependencies": { - "com.bytedance.napi": "file:../LocalPackages/com.bytedance.napi", "com.unity.2d.animation": "3.2.3", "com.unity.2d.pixel-perfect": "2.0.4", "com.unity.2d.psdimporter": "2.1.4",