pax_global_header00006660000000000000000000000064137402272670014524gustar00rootroot0000000000000052 comment=88fc14ae6dc5ff6eed704407e5f72ff0d28a7013 kcp-go-5.6.1/000077500000000000000000000000001374022726700127155ustar00rootroot00000000000000kcp-go-5.6.1/.gitignore000066400000000000000000000004231374022726700147040ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test /vendor/ # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof kcp-go-5.6.1/.travis.yml000066400000000000000000000005051374022726700150260ustar00rootroot00000000000000language: go go: - 1.11.x - 1.12.x - 1.13.x env: - GO111MODULE=on before_install: - go get -t -v ./... install: - go get github.com/xtaci/kcp-go script: - go test -coverprofile=coverage.txt -covermode=atomic -bench . -timeout 10m after_success: - bash <(curl -s https://codecov.io/bash) kcp-go-5.6.1/LICENSE000066400000000000000000000020651374022726700137250ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Daniel Fu 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. kcp-go-5.6.1/README.md000066400000000000000000000442541374022726700142050ustar00rootroot00000000000000kcp-go [![GoDoc][1]][2] [![Powered][9]][10] [![MIT licensed][11]][12] [![Build Status][3]][4] [![Go Report Card][5]][6] [![Coverage Statusd][7]][8] [![Sourcegraph][13]][14] [1]: https://godoc.org/github.com/xtaci/kcp-go?status.svg [2]: https://pkg.go.dev/github.com/xtaci/kcp-go [3]: https://travis-ci.org/xtaci/kcp-go.svg?branch=master [4]: https://travis-ci.org/xtaci/kcp-go [5]: https://goreportcard.com/badge/github.com/xtaci/kcp-go [6]: https://goreportcard.com/report/github.com/xtaci/kcp-go [7]: https://codecov.io/gh/xtaci/kcp-go/branch/master/graph/badge.svg [8]: https://codecov.io/gh/xtaci/kcp-go [9]: https://img.shields.io/badge/KCP-Powered-blue.svg [10]: https://github.com/skywind3000/kcp [11]: https://img.shields.io/badge/license-MIT-blue.svg [12]: LICENSE [13]: https://sourcegraph.com/github.com/xtaci/kcp-go/-/badge.svg [14]: https://sourcegraph.com/github.com/xtaci/kcp-go?badge ## Introduction **kcp-go** is a **Production-Grade Reliable-UDP** library for [golang](https://golang.org/). This library intents to provide a **smooth, resilient, ordered, error-checked and anonymous** delivery of streams over **UDP** packets, it has been battle-tested with opensource project [kcptun](https://github.com/xtaci/kcptun). Millions of devices(from low-end MIPS routers to high-end servers) have deployed **kcp-go** powered program in a variety of forms like **online games, live broadcasting, file synchronization and network acceleration**. [Lastest Release](https://github.com/xtaci/kcp-go/releases) ## Features 1. Designed for **Latency-sensitive** scenarios. 1. **Cache friendly** and **Memory optimized** design, offers extremely **High Performance** core. 1. Handles **>5K concurrent connections** on a single commodity server. 1. Compatible with [net.Conn](https://golang.org/pkg/net/#Conn) and [net.Listener](https://golang.org/pkg/net/#Listener), a drop-in replacement for [net.TCPConn](https://golang.org/pkg/net/#TCPConn). 1. [FEC(Forward Error Correction)](https://en.wikipedia.org/wiki/Forward_error_correction) Support with [Reed-Solomon Codes](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction) 1. Packet level encryption support with [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard), [TEA](https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm), [3DES](https://en.wikipedia.org/wiki/Triple_DES), [Blowfish](https://en.wikipedia.org/wiki/Blowfish_(cipher)), [Cast5](https://en.wikipedia.org/wiki/CAST-128), [Salsa20]( https://en.wikipedia.org/wiki/Salsa20), etc. in [CFB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Feedback_.28CFB.29) mode, which generates completely anonymous packet. 1. Only **A fixed number of goroutines** will be created for the entire server application, costs in **context switch** between goroutines have been taken into consideration. 1. Compatible with [skywind3000's](https://github.com/skywind3000) C version with various improvements. 1. Platform-dependent optimizations: [sendmmsg](http://man7.org/linux/man-pages/man2/sendmmsg.2.html) and [recvmmsg](http://man7.org/linux/man-pages/man2/recvmmsg.2.html) were expoloited for linux. ## Documentation For complete documentation, see the associated [Godoc](https://godoc.org/github.com/xtaci/kcp-go). ## Specification Frame Format ``` NONCE: 16bytes cryptographically secure random number, nonce changes for every packet. CRC32: CRC-32 checksum of data using the IEEE polynomial FEC TYPE: typeData = 0xF1 typeParity = 0xF2 FEC SEQID: monotonically increasing in range: [0, (0xffffffff/shardSize) * shardSize - 1] SIZE: The size of KCP frame plus 2 ``` ``` +-----------------+ | SESSION | +-----------------+ | KCP(ARQ) | +-----------------+ | FEC(OPTIONAL) | +-----------------+ | CRYPTO(OPTIONAL)| +-----------------+ | UDP(PACKET) | +-----------------+ | IP | +-----------------+ | LINK | +-----------------+ | PHY | +-----------------+ (LAYER MODEL OF KCP-GO) ``` ## Examples 1. [simple examples](https://github.com/xtaci/kcp-go/tree/master/examples) 2. [kcptun client](https://github.com/xtaci/kcptun/blob/master/client/main.go) 3. [kcptun server](https://github.com/xtaci/kcptun/blob/master/server/main.go) ## Benchmark ``` === Model Name: MacBook Pro Model Identifier: MacBookPro14,1 Processor Name: Intel Core i5 Processor Speed: 3.1 GHz Number of Processors: 1 Total Number of Cores: 2 L2 Cache (per Core): 256 KB L3 Cache: 4 MB Memory: 8 GB === $ go test -v -run=^$ -bench . beginning tests, encryption:salsa20, fec:10/3 goos: darwin goarch: amd64 pkg: github.com/xtaci/kcp-go BenchmarkSM4-4 50000 32180 ns/op 93.23 MB/s 0 B/op 0 allocs/op BenchmarkAES128-4 500000 3285 ns/op 913.21 MB/s 0 B/op 0 allocs/op BenchmarkAES192-4 300000 3623 ns/op 827.85 MB/s 0 B/op 0 allocs/op BenchmarkAES256-4 300000 3874 ns/op 774.20 MB/s 0 B/op 0 allocs/op BenchmarkTEA-4 100000 15384 ns/op 195.00 MB/s 0 B/op 0 allocs/op BenchmarkXOR-4 20000000 89.9 ns/op 33372.00 MB/s 0 B/op 0 allocs/op BenchmarkBlowfish-4 50000 26927 ns/op 111.41 MB/s 0 B/op 0 allocs/op BenchmarkNone-4 30000000 45.7 ns/op 65597.94 MB/s 0 B/op 0 allocs/op BenchmarkCast5-4 50000 34258 ns/op 87.57 MB/s 0 B/op 0 allocs/op Benchmark3DES-4 10000 117149 ns/op 25.61 MB/s 0 B/op 0 allocs/op BenchmarkTwofish-4 50000 33538 ns/op 89.45 MB/s 0 B/op 0 allocs/op BenchmarkXTEA-4 30000 45666 ns/op 65.69 MB/s 0 B/op 0 allocs/op BenchmarkSalsa20-4 500000 3308 ns/op 906.76 MB/s 0 B/op 0 allocs/op BenchmarkCRC32-4 20000000 65.2 ns/op 15712.43 MB/s BenchmarkCsprngSystem-4 1000000 1150 ns/op 13.91 MB/s BenchmarkCsprngMD5-4 10000000 145 ns/op 110.26 MB/s BenchmarkCsprngSHA1-4 10000000 158 ns/op 126.54 MB/s BenchmarkCsprngNonceMD5-4 10000000 153 ns/op 104.22 MB/s BenchmarkCsprngNonceAES128-4 100000000 19.1 ns/op 837.81 MB/s BenchmarkFECDecode-4 1000000 1119 ns/op 1339.61 MB/s 1606 B/op 2 allocs/op BenchmarkFECEncode-4 2000000 832 ns/op 1801.83 MB/s 17 B/op 0 allocs/op BenchmarkFlush-4 5000000 272 ns/op 0 B/op 0 allocs/op BenchmarkEchoSpeed4K-4 5000 259617 ns/op 15.78 MB/s 5451 B/op 149 allocs/op BenchmarkEchoSpeed64K-4 1000 1706084 ns/op 38.41 MB/s 56002 B/op 1604 allocs/op BenchmarkEchoSpeed512K-4 100 14345505 ns/op 36.55 MB/s 482597 B/op 13045 allocs/op BenchmarkEchoSpeed1M-4 30 34859104 ns/op 30.08 MB/s 1143773 B/op 27186 allocs/op BenchmarkSinkSpeed4K-4 50000 31369 ns/op 130.57 MB/s 1566 B/op 30 allocs/op BenchmarkSinkSpeed64K-4 5000 329065 ns/op 199.16 MB/s 21529 B/op 453 allocs/op BenchmarkSinkSpeed256K-4 500 2373354 ns/op 220.91 MB/s 166332 B/op 3554 allocs/op BenchmarkSinkSpeed1M-4 300 5117927 ns/op 204.88 MB/s 310378 B/op 6988 allocs/op PASS ok github.com/xtaci/kcp-go 50.349s ``` ``` === Raspberry Pi 4 === ➜ kcp-go git:(master) cat /proc/cpuinfo processor : 0 model name : ARMv7 Processor rev 3 (v7l) BogoMIPS : 108.00 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3 ➜ kcp-go git:(master) go test -run=^$ -bench . 2020/01/05 19:25:13 beginning tests, encryption:salsa20, fec:10/3 goos: linux goarch: arm pkg: github.com/xtaci/kcp-go/v5 BenchmarkSM4-4 20000 86475 ns/op 34.69 MB/s 0 B/op 0 allocs/op BenchmarkAES128-4 20000 62254 ns/op 48.19 MB/s 0 B/op 0 allocs/op BenchmarkAES192-4 20000 71802 ns/op 41.78 MB/s 0 B/op 0 allocs/op BenchmarkAES256-4 20000 80570 ns/op 37.23 MB/s 0 B/op 0 allocs/op BenchmarkTEA-4 50000 37343 ns/op 80.34 MB/s 0 B/op 0 allocs/op BenchmarkXOR-4 100000 22266 ns/op 134.73 MB/s 0 B/op 0 allocs/op BenchmarkBlowfish-4 20000 66123 ns/op 45.37 MB/s 0 B/op 0 allocs/op BenchmarkNone-4 3000000 518 ns/op 5786.77 MB/s 0 B/op 0 allocs/op BenchmarkCast5-4 20000 76705 ns/op 39.11 MB/s 0 B/op 0 allocs/op Benchmark3DES-4 5000 418868 ns/op 7.16 MB/s 0 B/op 0 allocs/op BenchmarkTwofish-4 5000 326896 ns/op 9.18 MB/s 0 B/op 0 allocs/op BenchmarkXTEA-4 10000 114418 ns/op 26.22 MB/s 0 B/op 0 allocs/op BenchmarkSalsa20-4 50000 36736 ns/op 81.66 MB/s 0 B/op 0 allocs/op BenchmarkCRC32-4 1000000 1735 ns/op 589.98 MB/s BenchmarkCsprngSystem-4 1000000 2179 ns/op 7.34 MB/s BenchmarkCsprngMD5-4 2000000 811 ns/op 19.71 MB/s BenchmarkCsprngSHA1-4 2000000 862 ns/op 23.19 MB/s BenchmarkCsprngNonceMD5-4 2000000 878 ns/op 18.22 MB/s BenchmarkCsprngNonceAES128-4 5000000 326 ns/op 48.97 MB/s BenchmarkFECDecode-4 200000 9081 ns/op 165.16 MB/s 140 B/op 1 allocs/op BenchmarkFECEncode-4 100000 12039 ns/op 124.59 MB/s 11 B/op 0 allocs/op BenchmarkFlush-4 100000 21704 ns/op 0 B/op 0 allocs/op BenchmarkEchoSpeed4K-4 2000 981182 ns/op 4.17 MB/s 12384 B/op 424 allocs/op BenchmarkEchoSpeed64K-4 100 10503324 ns/op 6.24 MB/s 123616 B/op 3779 allocs/op BenchmarkEchoSpeed512K-4 20 138633802 ns/op 3.78 MB/s 1606584 B/op 29233 allocs/op BenchmarkEchoSpeed1M-4 5 372903568 ns/op 2.81 MB/s 4080504 B/op 63600 allocs/op BenchmarkSinkSpeed4K-4 10000 121239 ns/op 33.78 MB/s 4647 B/op 104 allocs/op BenchmarkSinkSpeed64K-4 1000 1587906 ns/op 41.27 MB/s 50914 B/op 1115 allocs/op BenchmarkSinkSpeed256K-4 100 16277830 ns/op 32.21 MB/s 453027 B/op 9296 allocs/op BenchmarkSinkSpeed1M-4 100 31040703 ns/op 33.78 MB/s 898097 B/op 18932 allocs/op PASS ok github.com/xtaci/kcp-go/v5 64.151s ``` ## Typical Flame Graph ![Flame Graph in kcptun](flame.png) ## Key Design Considerations 1. slice vs. container/list `kcp.flush()` loops through the send queue for retransmission checking for every 20ms(interval). I've wrote a benchmark for comparing sequential loop through *slice* and *container/list* here: https://github.com/xtaci/notes/blob/master/golang/benchmark2/cachemiss_test.go ``` BenchmarkLoopSlice-4 2000000000 0.39 ns/op BenchmarkLoopList-4 100000000 54.6 ns/op ``` List structure introduces **heavy cache misses** compared to slice which owns better **locality**, 5000 connections with 32 window size and 20ms interval will cost 6us/0.03%(cpu) using slice, and 8.7ms/43.5%(cpu) for list for each `kcp.flush()`. 2. Timing accuracy vs. syscall clock_gettime Timing is **critical** to **RTT estimator**, inaccurate timing leads to false retransmissions in KCP, but calling `time.Now()` costs 42 cycles(10.5ns on 4GHz CPU, 15.6ns on my MacBook Pro 2.7GHz). The benchmark for time.Now() lies here: https://github.com/xtaci/notes/blob/master/golang/benchmark2/syscall_test.go ``` BenchmarkNow-4 100000000 15.6 ns/op ``` In kcp-go, after each `kcp.output()` function call, current clock time will be updated upon return, and for a single `kcp.flush()` operation, current time will be queried from system once. For most of the time, 5000 connections costs 5000 * 15.6ns = 78us(a fixed cost while no packet needs to be sent), as for 10MB/s data transfering with 1400 MTU, `kcp.output()` will be called around 7500 times and costs 117us for `time.Now()` in **every second**. 3. Memory management Primary memory allocation are done from a global buffer pool xmit.Buf, in kcp-go, when we need to allocate some bytes, we can get from that pool, and a fixed-capacity 1500 bytes(mtuLimit) will be returned, the rx queue, tx queue and fec queue all receive bytes from there, and they will return the bytes to the pool after using to prevent unnecessary zer0ing of bytes. The pool mechanism maintained a high watermark for slice objects, these in-flight objects from the pool will survive from the perodical garbage collection, meanwhile the pool kept the ability to return the memory to runtime if in idle. 4. Information security kcp-go is shipped with builtin packet encryption powered by various block encryption algorithms and works in [Cipher Feedback Mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Feedback_(CFB)), for each packet to be sent, the encryption process will start from encrypting a [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) from the [system entropy](https://en.wikipedia.org/wiki//dev/random), so encryption to same plaintexts never leads to a same ciphertexts thereafter. The contents of the packets are completely anonymous with encryption, including the headers(FEC,KCP), checksums and contents. Note that, no matter which encryption method you choose on you upper layer, if you disable encryption, the transmit will be insecure somehow, since the header is ***PLAINTEXT*** to everyone it would be susceptible to header tampering, such as jamming the *sliding window size*, *round-trip time*, *FEC property* and *checksums*. ```AES-128``` is suggested for minimal encryption since modern CPUs are shipped with [AES-NI](https://en.wikipedia.org/wiki/AES_instruction_set) instructions and performs even better than `salsa20`(check the table above). Other possible attacks to kcp-go includes: a) [traffic analysis](https://en.wikipedia.org/wiki/Traffic_analysis), dataflow on specific websites may have pattern while interchanging data, but this type of eavesdropping has been mitigated by adapting [smux](https://github.com/xtaci/smux) to mix data streams so as to introduce noises, perfect solution to this has not appeared yet, theroretically by shuffling/mixing messages on larger scale network may mitigate this problem. b) [replay attack](https://en.wikipedia.org/wiki/Replay_attack), since the asymmetrical encryption has not been introduced into kcp-go for some reason, capturing the packets and replay them on a different machine is possible, (notice: hijacking the session and decrypting the contents is still *impossible*), so upper layers should contain a asymmetrical encryption system to guarantee the authenticity of each message(to process message exactly once), such as HTTPS/OpenSSL/LibreSSL, only by signing the requests with private keys can eliminate this type of attack. ## Connection Termination Control messages like **SYN/FIN/RST** in TCP **are not defined** in KCP, you need some **keepalive/heartbeat mechanism** in the application-level. A real world example is to use some **multiplexing** protocol over session, such as [smux](https://github.com/xtaci/smux)(with embedded keepalive mechanism), see [kcptun](https://github.com/xtaci/kcptun) for example. ## FAQ Q: I'm handling >5K connections on my server, the CPU utilization is so high. A: A standalone `agent` or `gate` server for running kcp-go is suggested, not only for CPU utilization, but also important to the **precision** of RTT measurements(timing) which indirectly affects retransmission. By increasing update `interval` with `SetNoDelay` like `conn.SetNoDelay(1, 40, 1, 1)` will dramatically reduce system load, but lower the performance. Q: When should I enable FEC? A: Forward error correction is critical to long-distance transmission, because a packet loss will lead to a huge penalty in time. And for the complicated packet routing network in modern world, round-trip time based loss check will not always be efficient, the big deviation of RTT samples in the long way usually leads to a larger RTO value in typical rtt estimator, which in other words, slows down the transmission. Q: Should I enable encryption? A: Yes, for the safety of protocol, even if the upper layer has encrypted. ## Who is using this? 1. https://github.com/xtaci/kcptun -- A Secure Tunnel Based On KCP over UDP. 2. https://github.com/getlantern/lantern -- Lantern delivers fast access to the open Internet. 3. https://github.com/smallnest/rpcx -- A RPC service framework based on net/rpc like alibaba Dubbo and weibo Motan. 4. https://github.com/gonet2/agent -- A gateway for games with stream multiplexing. 5. https://github.com/syncthing/syncthing -- Open Source Continuous File Synchronization. ## Links 1. https://github.com/xtaci/smux/ -- A Stream Multiplexing Library for golang with least memory 1. https://github.com/xtaci/libkcp -- FEC enhanced KCP session library for iOS/Android in C++ 1. https://github.com/skywind3000/kcp -- A Fast and Reliable ARQ Protocol 1. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go ## Consulting WeChat(付费技术咨询) kcptun kcp-go-5.6.1/autotune.go000066400000000000000000000026611374022726700151150ustar00rootroot00000000000000package kcp const maxAutoTuneSamples = 258 // pulse represents a 0/1 signal with time sequence type pulse struct { bit bool // 0 or 1 seq uint32 // sequence of the signal } // autoTune object type autoTune struct { pulses [maxAutoTuneSamples]pulse } // Sample adds a signal sample to the pulse buffer func (tune *autoTune) Sample(bit bool, seq uint32) { tune.pulses[seq%maxAutoTuneSamples] = pulse{bit, seq} } // Find a period for a given signal // returns -1 if not found // // --- ------ // | | // |______________| // Period // Falling Edge Rising Edge func (tune *autoTune) FindPeriod(bit bool) int { // last pulse and initial index setup lastPulse := tune.pulses[0] idx := 1 // left edge var leftEdge int for ; idx < len(tune.pulses); idx++ { if lastPulse.bit != bit && tune.pulses[idx].bit == bit { // edge found if lastPulse.seq+1 == tune.pulses[idx].seq { // ensure edge continuity leftEdge = idx break } } lastPulse = tune.pulses[idx] } // right edge var rightEdge int lastPulse = tune.pulses[leftEdge] idx = leftEdge + 1 for ; idx < len(tune.pulses); idx++ { if lastPulse.seq+1 == tune.pulses[idx].seq { // ensure pulses in this level monotonic if lastPulse.bit == bit && tune.pulses[idx].bit != bit { // edge found rightEdge = idx break } } else { return -1 } lastPulse = tune.pulses[idx] } return rightEdge - leftEdge } kcp-go-5.6.1/autotune_test.go000066400000000000000000000017251374022726700161540ustar00rootroot00000000000000package kcp import ( "testing" "github.com/stretchr/testify/assert" ) func TestAutoTune(t *testing.T) { signals := []uint32{0, 0, 0, 0, 0, 0} tune := autoTune{} for i := 0; i < len(signals); i++ { if signals[i] == 0 { tune.Sample(false, uint32(i)) } else { tune.Sample(true, uint32(i)) } } assert.Equal(t, -1, tune.FindPeriod(false)) assert.Equal(t, -1, tune.FindPeriod(true)) signals = []uint32{1, 0, 1, 0, 0, 1} tune = autoTune{} for i := 0; i < len(signals); i++ { if signals[i] == 0 { tune.Sample(false, uint32(i)) } else { tune.Sample(true, uint32(i)) } } assert.Equal(t, 1, tune.FindPeriod(false)) assert.Equal(t, 1, tune.FindPeriod(true)) signals = []uint32{1, 0, 0, 0, 0, 1} tune = autoTune{} for i := 0; i < len(signals); i++ { if signals[i] == 0 { tune.Sample(false, uint32(i)) } else { tune.Sample(true, uint32(i)) } } assert.Equal(t, -1, tune.FindPeriod(true)) assert.Equal(t, 4, tune.FindPeriod(false)) } kcp-go-5.6.1/batchconn.go000066400000000000000000000003221374022726700152000ustar00rootroot00000000000000package kcp import "golang.org/x/net/ipv4" const ( batchSize = 16 ) type batchConn interface { WriteBatch(ms []ipv4.Message, flags int) (int, error) ReadBatch(ms []ipv4.Message, flags int) (int, error) } kcp-go-5.6.1/crypt.go000066400000000000000000000412461374022726700144140ustar00rootroot00000000000000package kcp import ( "crypto/aes" "crypto/cipher" "crypto/des" "crypto/sha1" "unsafe" xor "github.com/templexxx/xorsimd" "github.com/tjfoc/gmsm/sm4" "golang.org/x/crypto/blowfish" "golang.org/x/crypto/cast5" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/salsa20" "golang.org/x/crypto/tea" "golang.org/x/crypto/twofish" "golang.org/x/crypto/xtea" ) var ( initialVector = []byte{167, 115, 79, 156, 18, 172, 27, 1, 164, 21, 242, 193, 252, 120, 230, 107} saltxor = `sH3CIVoF#rWLtJo6` ) // BlockCrypt defines encryption/decryption methods for a given byte slice. // Notes on implementing: the data to be encrypted contains a builtin // nonce at the first 16 bytes type BlockCrypt interface { // Encrypt encrypts the whole block in src into dst. // Dst and src may point at the same memory. Encrypt(dst, src []byte) // Decrypt decrypts the whole block in src into dst. // Dst and src may point at the same memory. Decrypt(dst, src []byte) } type salsa20BlockCrypt struct { key [32]byte } // NewSalsa20BlockCrypt https://en.wikipedia.org/wiki/Salsa20 func NewSalsa20BlockCrypt(key []byte) (BlockCrypt, error) { c := new(salsa20BlockCrypt) copy(c.key[:], key) return c, nil } func (c *salsa20BlockCrypt) Encrypt(dst, src []byte) { salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key) copy(dst[:8], src[:8]) } func (c *salsa20BlockCrypt) Decrypt(dst, src []byte) { salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key) copy(dst[:8], src[:8]) } type sm4BlockCrypt struct { encbuf [sm4.BlockSize]byte // 64bit alignment enc/dec buffer decbuf [2 * sm4.BlockSize]byte block cipher.Block } // NewSM4BlockCrypt https://github.com/tjfoc/gmsm/tree/master/sm4 func NewSM4BlockCrypt(key []byte) (BlockCrypt, error) { c := new(sm4BlockCrypt) block, err := sm4.NewCipher(key) if err != nil { return nil, err } c.block = block return c, nil } func (c *sm4BlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } func (c *sm4BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } type twofishBlockCrypt struct { encbuf [twofish.BlockSize]byte decbuf [2 * twofish.BlockSize]byte block cipher.Block } // NewTwofishBlockCrypt https://en.wikipedia.org/wiki/Twofish func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) { c := new(twofishBlockCrypt) block, err := twofish.NewCipher(key) if err != nil { return nil, err } c.block = block return c, nil } func (c *twofishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } func (c *twofishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } type tripleDESBlockCrypt struct { encbuf [des.BlockSize]byte decbuf [2 * des.BlockSize]byte block cipher.Block } // NewTripleDESBlockCrypt https://en.wikipedia.org/wiki/Triple_DES func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) { c := new(tripleDESBlockCrypt) block, err := des.NewTripleDESCipher(key) if err != nil { return nil, err } c.block = block return c, nil } func (c *tripleDESBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } func (c *tripleDESBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } type cast5BlockCrypt struct { encbuf [cast5.BlockSize]byte decbuf [2 * cast5.BlockSize]byte block cipher.Block } // NewCast5BlockCrypt https://en.wikipedia.org/wiki/CAST-128 func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) { c := new(cast5BlockCrypt) block, err := cast5.NewCipher(key) if err != nil { return nil, err } c.block = block return c, nil } func (c *cast5BlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } func (c *cast5BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } type blowfishBlockCrypt struct { encbuf [blowfish.BlockSize]byte decbuf [2 * blowfish.BlockSize]byte block cipher.Block } // NewBlowfishBlockCrypt https://en.wikipedia.org/wiki/Blowfish_(cipher) func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) { c := new(blowfishBlockCrypt) block, err := blowfish.NewCipher(key) if err != nil { return nil, err } c.block = block return c, nil } func (c *blowfishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } func (c *blowfishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } type aesBlockCrypt struct { encbuf [aes.BlockSize]byte decbuf [2 * aes.BlockSize]byte block cipher.Block } // NewAESBlockCrypt https://en.wikipedia.org/wiki/Advanced_Encryption_Standard func NewAESBlockCrypt(key []byte) (BlockCrypt, error) { c := new(aesBlockCrypt) block, err := aes.NewCipher(key) if err != nil { return nil, err } c.block = block return c, nil } func (c *aesBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } func (c *aesBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } type teaBlockCrypt struct { encbuf [tea.BlockSize]byte decbuf [2 * tea.BlockSize]byte block cipher.Block } // NewTEABlockCrypt https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm func NewTEABlockCrypt(key []byte) (BlockCrypt, error) { c := new(teaBlockCrypt) block, err := tea.NewCipherWithRounds(key, 16) if err != nil { return nil, err } c.block = block return c, nil } func (c *teaBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } func (c *teaBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } type xteaBlockCrypt struct { encbuf [xtea.BlockSize]byte decbuf [2 * xtea.BlockSize]byte block cipher.Block } // NewXTEABlockCrypt https://en.wikipedia.org/wiki/XTEA func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) { c := new(xteaBlockCrypt) block, err := xtea.NewCipher(key) if err != nil { return nil, err } c.block = block return c, nil } func (c *xteaBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } func (c *xteaBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } type simpleXORBlockCrypt struct { xortbl []byte } // NewSimpleXORBlockCrypt simple xor with key expanding func NewSimpleXORBlockCrypt(key []byte) (BlockCrypt, error) { c := new(simpleXORBlockCrypt) c.xortbl = pbkdf2.Key(key, []byte(saltxor), 32, mtuLimit, sha1.New) return c, nil } func (c *simpleXORBlockCrypt) Encrypt(dst, src []byte) { xor.Bytes(dst, src, c.xortbl) } func (c *simpleXORBlockCrypt) Decrypt(dst, src []byte) { xor.Bytes(dst, src, c.xortbl) } type noneBlockCrypt struct{} // NewNoneBlockCrypt does nothing but copying func NewNoneBlockCrypt(key []byte) (BlockCrypt, error) { return new(noneBlockCrypt), nil } func (c *noneBlockCrypt) Encrypt(dst, src []byte) { copy(dst, src) } func (c *noneBlockCrypt) Decrypt(dst, src []byte) { copy(dst, src) } // packet encryption with local CFB mode func encrypt(block cipher.Block, dst, src, buf []byte) { switch block.BlockSize() { case 8: encrypt8(block, dst, src, buf) case 16: encrypt16(block, dst, src, buf) default: panic("unsupported cipher block size") } } // optimized encryption for the ciphers which works in 8-bytes func encrypt8(block cipher.Block, dst, src, buf []byte) { tbl := buf[:8] block.Encrypt(tbl, initialVector) n := len(src) / 8 base := 0 repeat := n / 8 left := n % 8 ptr_tbl := (*uint64)(unsafe.Pointer(&tbl[0])) for i := 0; i < repeat; i++ { s := src[base:][0:64] d := dst[base:][0:64] // 1 *(*uint64)(unsafe.Pointer(&d[0])) = *(*uint64)(unsafe.Pointer(&s[0])) ^ *ptr_tbl block.Encrypt(tbl, d[0:8]) // 2 *(*uint64)(unsafe.Pointer(&d[8])) = *(*uint64)(unsafe.Pointer(&s[8])) ^ *ptr_tbl block.Encrypt(tbl, d[8:16]) // 3 *(*uint64)(unsafe.Pointer(&d[16])) = *(*uint64)(unsafe.Pointer(&s[16])) ^ *ptr_tbl block.Encrypt(tbl, d[16:24]) // 4 *(*uint64)(unsafe.Pointer(&d[24])) = *(*uint64)(unsafe.Pointer(&s[24])) ^ *ptr_tbl block.Encrypt(tbl, d[24:32]) // 5 *(*uint64)(unsafe.Pointer(&d[32])) = *(*uint64)(unsafe.Pointer(&s[32])) ^ *ptr_tbl block.Encrypt(tbl, d[32:40]) // 6 *(*uint64)(unsafe.Pointer(&d[40])) = *(*uint64)(unsafe.Pointer(&s[40])) ^ *ptr_tbl block.Encrypt(tbl, d[40:48]) // 7 *(*uint64)(unsafe.Pointer(&d[48])) = *(*uint64)(unsafe.Pointer(&s[48])) ^ *ptr_tbl block.Encrypt(tbl, d[48:56]) // 8 *(*uint64)(unsafe.Pointer(&d[56])) = *(*uint64)(unsafe.Pointer(&s[56])) ^ *ptr_tbl block.Encrypt(tbl, d[56:64]) base += 64 } switch left { case 7: *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *ptr_tbl block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 6: *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *ptr_tbl block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 5: *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *ptr_tbl block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 4: *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *ptr_tbl block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 3: *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *ptr_tbl block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 2: *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *ptr_tbl block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 1: *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *ptr_tbl block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 0: xorBytes(dst[base:], src[base:], tbl) } } // optimized encryption for the ciphers which works in 16-bytes func encrypt16(block cipher.Block, dst, src, buf []byte) { tbl := buf[:16] block.Encrypt(tbl, initialVector) n := len(src) / 16 base := 0 repeat := n / 8 left := n % 8 for i := 0; i < repeat; i++ { s := src[base:][0:128] d := dst[base:][0:128] // 1 xor.Bytes16Align(d[0:16], s[0:16], tbl) block.Encrypt(tbl, d[0:16]) // 2 xor.Bytes16Align(d[16:32], s[16:32], tbl) block.Encrypt(tbl, d[16:32]) // 3 xor.Bytes16Align(d[32:48], s[32:48], tbl) block.Encrypt(tbl, d[32:48]) // 4 xor.Bytes16Align(d[48:64], s[48:64], tbl) block.Encrypt(tbl, d[48:64]) // 5 xor.Bytes16Align(d[64:80], s[64:80], tbl) block.Encrypt(tbl, d[64:80]) // 6 xor.Bytes16Align(d[80:96], s[80:96], tbl) block.Encrypt(tbl, d[80:96]) // 7 xor.Bytes16Align(d[96:112], s[96:112], tbl) block.Encrypt(tbl, d[96:112]) // 8 xor.Bytes16Align(d[112:128], s[112:128], tbl) block.Encrypt(tbl, d[112:128]) base += 128 } switch left { case 7: xor.Bytes16Align(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 6: xor.Bytes16Align(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 5: xor.Bytes16Align(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 4: xor.Bytes16Align(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 3: xor.Bytes16Align(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 2: xor.Bytes16Align(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 1: xor.Bytes16Align(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 0: xorBytes(dst[base:], src[base:], tbl) } } // decryption func decrypt(block cipher.Block, dst, src, buf []byte) { switch block.BlockSize() { case 8: decrypt8(block, dst, src, buf) case 16: decrypt16(block, dst, src, buf) default: panic("unsupported cipher block size") } } // decrypt 8 bytes block, all byte slices are supposed to be 64bit aligned func decrypt8(block cipher.Block, dst, src, buf []byte) { tbl := buf[0:8] next := buf[8:16] block.Encrypt(tbl, initialVector) n := len(src) / 8 base := 0 repeat := n / 8 left := n % 8 ptr_tbl := (*uint64)(unsafe.Pointer(&tbl[0])) ptr_next := (*uint64)(unsafe.Pointer(&next[0])) for i := 0; i < repeat; i++ { s := src[base:][0:64] d := dst[base:][0:64] // 1 block.Encrypt(next, s[0:8]) *(*uint64)(unsafe.Pointer(&d[0])) = *(*uint64)(unsafe.Pointer(&s[0])) ^ *ptr_tbl // 2 block.Encrypt(tbl, s[8:16]) *(*uint64)(unsafe.Pointer(&d[8])) = *(*uint64)(unsafe.Pointer(&s[8])) ^ *ptr_next // 3 block.Encrypt(next, s[16:24]) *(*uint64)(unsafe.Pointer(&d[16])) = *(*uint64)(unsafe.Pointer(&s[16])) ^ *ptr_tbl // 4 block.Encrypt(tbl, s[24:32]) *(*uint64)(unsafe.Pointer(&d[24])) = *(*uint64)(unsafe.Pointer(&s[24])) ^ *ptr_next // 5 block.Encrypt(next, s[32:40]) *(*uint64)(unsafe.Pointer(&d[32])) = *(*uint64)(unsafe.Pointer(&s[32])) ^ *ptr_tbl // 6 block.Encrypt(tbl, s[40:48]) *(*uint64)(unsafe.Pointer(&d[40])) = *(*uint64)(unsafe.Pointer(&s[40])) ^ *ptr_next // 7 block.Encrypt(next, s[48:56]) *(*uint64)(unsafe.Pointer(&d[48])) = *(*uint64)(unsafe.Pointer(&s[48])) ^ *ptr_tbl // 8 block.Encrypt(tbl, s[56:64]) *(*uint64)(unsafe.Pointer(&d[56])) = *(*uint64)(unsafe.Pointer(&s[56])) ^ *ptr_next base += 64 } switch left { case 7: block.Encrypt(next, src[base:]) *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *(*uint64)(unsafe.Pointer(&tbl[0])) tbl, next = next, tbl base += 8 fallthrough case 6: block.Encrypt(next, src[base:]) *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *(*uint64)(unsafe.Pointer(&tbl[0])) tbl, next = next, tbl base += 8 fallthrough case 5: block.Encrypt(next, src[base:]) *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *(*uint64)(unsafe.Pointer(&tbl[0])) tbl, next = next, tbl base += 8 fallthrough case 4: block.Encrypt(next, src[base:]) *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *(*uint64)(unsafe.Pointer(&tbl[0])) tbl, next = next, tbl base += 8 fallthrough case 3: block.Encrypt(next, src[base:]) *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *(*uint64)(unsafe.Pointer(&tbl[0])) tbl, next = next, tbl base += 8 fallthrough case 2: block.Encrypt(next, src[base:]) *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *(*uint64)(unsafe.Pointer(&tbl[0])) tbl, next = next, tbl base += 8 fallthrough case 1: block.Encrypt(next, src[base:]) *(*uint64)(unsafe.Pointer(&dst[base])) = *(*uint64)(unsafe.Pointer(&src[base])) ^ *(*uint64)(unsafe.Pointer(&tbl[0])) tbl, next = next, tbl base += 8 fallthrough case 0: xorBytes(dst[base:], src[base:], tbl) } } func decrypt16(block cipher.Block, dst, src, buf []byte) { tbl := buf[0:16] next := buf[16:32] block.Encrypt(tbl, initialVector) n := len(src) / 16 base := 0 repeat := n / 8 left := n % 8 for i := 0; i < repeat; i++ { s := src[base:][0:128] d := dst[base:][0:128] // 1 block.Encrypt(next, s[0:16]) xor.Bytes16Align(d[0:16], s[0:16], tbl) // 2 block.Encrypt(tbl, s[16:32]) xor.Bytes16Align(d[16:32], s[16:32], next) // 3 block.Encrypt(next, s[32:48]) xor.Bytes16Align(d[32:48], s[32:48], tbl) // 4 block.Encrypt(tbl, s[48:64]) xor.Bytes16Align(d[48:64], s[48:64], next) // 5 block.Encrypt(next, s[64:80]) xor.Bytes16Align(d[64:80], s[64:80], tbl) // 6 block.Encrypt(tbl, s[80:96]) xor.Bytes16Align(d[80:96], s[80:96], next) // 7 block.Encrypt(next, s[96:112]) xor.Bytes16Align(d[96:112], s[96:112], tbl) // 8 block.Encrypt(tbl, s[112:128]) xor.Bytes16Align(d[112:128], s[112:128], next) base += 128 } switch left { case 7: block.Encrypt(next, src[base:]) xor.Bytes16Align(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 6: block.Encrypt(next, src[base:]) xor.Bytes16Align(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 5: block.Encrypt(next, src[base:]) xor.Bytes16Align(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 4: block.Encrypt(next, src[base:]) xor.Bytes16Align(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 3: block.Encrypt(next, src[base:]) xor.Bytes16Align(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 2: block.Encrypt(next, src[base:]) xor.Bytes16Align(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 1: block.Encrypt(next, src[base:]) xor.Bytes16Align(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 0: xorBytes(dst[base:], src[base:], tbl) } } // per bytes xors func xorBytes(dst, a, b []byte) int { n := len(a) if len(b) < n { n = len(b) } if n == 0 { return 0 } for i := 0; i < n; i++ { dst[i] = a[i] ^ b[i] } return n } kcp-go-5.6.1/crypt_test.go000066400000000000000000000114431374022726700154470ustar00rootroot00000000000000package kcp import ( "bytes" "crypto/aes" "crypto/md5" "crypto/rand" "crypto/sha1" "hash/crc32" "io" "testing" ) func TestSM4(t *testing.T) { bc, err := NewSM4BlockCrypt(pass[:16]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestAES(t *testing.T) { bc, err := NewAESBlockCrypt(pass[:32]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestTEA(t *testing.T) { bc, err := NewTEABlockCrypt(pass[:16]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestXOR(t *testing.T) { bc, err := NewSimpleXORBlockCrypt(pass[:32]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestBlowfish(t *testing.T) { bc, err := NewBlowfishBlockCrypt(pass[:32]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestNone(t *testing.T) { bc, err := NewNoneBlockCrypt(pass[:32]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestCast5(t *testing.T) { bc, err := NewCast5BlockCrypt(pass[:16]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func Test3DES(t *testing.T) { bc, err := NewTripleDESBlockCrypt(pass[:24]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestTwofish(t *testing.T) { bc, err := NewTwofishBlockCrypt(pass[:32]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestXTEA(t *testing.T) { bc, err := NewXTEABlockCrypt(pass[:16]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func TestSalsa20(t *testing.T) { bc, err := NewSalsa20BlockCrypt(pass[:32]) if err != nil { t.Fatal(err) } cryptTest(t, bc) } func cryptTest(t *testing.T, bc BlockCrypt) { data := make([]byte, mtuLimit) io.ReadFull(rand.Reader, data) dec := make([]byte, mtuLimit) enc := make([]byte, mtuLimit) bc.Encrypt(enc, data) bc.Decrypt(dec, enc) if !bytes.Equal(data, dec) { t.Fail() } } func BenchmarkSM4(b *testing.B) { bc, err := NewSM4BlockCrypt(pass[:16]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkAES128(b *testing.B) { bc, err := NewAESBlockCrypt(pass[:16]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkAES192(b *testing.B) { bc, err := NewAESBlockCrypt(pass[:24]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkAES256(b *testing.B) { bc, err := NewAESBlockCrypt(pass[:32]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkTEA(b *testing.B) { bc, err := NewTEABlockCrypt(pass[:16]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkXOR(b *testing.B) { bc, err := NewSimpleXORBlockCrypt(pass[:32]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkBlowfish(b *testing.B) { bc, err := NewBlowfishBlockCrypt(pass[:32]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkNone(b *testing.B) { bc, err := NewNoneBlockCrypt(pass[:32]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkCast5(b *testing.B) { bc, err := NewCast5BlockCrypt(pass[:16]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func Benchmark3DES(b *testing.B) { bc, err := NewTripleDESBlockCrypt(pass[:24]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkTwofish(b *testing.B) { bc, err := NewTwofishBlockCrypt(pass[:32]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkXTEA(b *testing.B) { bc, err := NewXTEABlockCrypt(pass[:16]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func BenchmarkSalsa20(b *testing.B) { bc, err := NewSalsa20BlockCrypt(pass[:32]) if err != nil { b.Fatal(err) } benchCrypt(b, bc) } func benchCrypt(b *testing.B, bc BlockCrypt) { data := make([]byte, mtuLimit) io.ReadFull(rand.Reader, data) dec := make([]byte, mtuLimit) enc := make([]byte, mtuLimit) b.ReportAllocs() b.SetBytes(int64(len(enc) * 2)) b.ResetTimer() for i := 0; i < b.N; i++ { bc.Encrypt(enc, data) bc.Decrypt(dec, enc) } } func BenchmarkCRC32(b *testing.B) { content := make([]byte, 1024) b.SetBytes(int64(len(content))) for i := 0; i < b.N; i++ { crc32.ChecksumIEEE(content) } } func BenchmarkCsprngSystem(b *testing.B) { data := make([]byte, md5.Size) b.SetBytes(int64(len(data))) for i := 0; i < b.N; i++ { io.ReadFull(rand.Reader, data) } } func BenchmarkCsprngMD5(b *testing.B) { var data [md5.Size]byte b.SetBytes(md5.Size) for i := 0; i < b.N; i++ { data = md5.Sum(data[:]) } } func BenchmarkCsprngSHA1(b *testing.B) { var data [sha1.Size]byte b.SetBytes(sha1.Size) for i := 0; i < b.N; i++ { data = sha1.Sum(data[:]) } } func BenchmarkCsprngNonceMD5(b *testing.B) { var ng nonceMD5 ng.Init() b.SetBytes(md5.Size) data := make([]byte, md5.Size) for i := 0; i < b.N; i++ { ng.Fill(data) } } func BenchmarkCsprngNonceAES128(b *testing.B) { var ng nonceAES128 ng.Init() b.SetBytes(aes.BlockSize) data := make([]byte, aes.BlockSize) for i := 0; i < b.N; i++ { ng.Fill(data) } } kcp-go-5.6.1/donate.png000066400000000000000000000105041374022726700146750ustar00rootroot00000000000000PNG  IHDR\rf IDATx}l'G}q˝k)!? <5ziU{чA A !F U<4 -J˃H/4=u/Ͽowvfvwv/c;cZk+91D"F#@ b`nZݦ-":-LO6qZ ?B|\DhܝͯoO2^K0'07e%E];qplEEDXĕ'SLѶ.p*UoJ+krV@hߣO˷Kw &e(N[yߗ6u jdMĨJ^Fq<~kU!^V?!keU"&3|]d"Kʟb^mSUv?џz, &I\Ni2Qk WMfaљ#_S8%R4~}(Oբ-6O2[߳Z}"dzdLqZ*]2/7^IUSTLʮrhdP.ȿ)Wlft6&:pd*ӯ0 X}Z>\somՙ`"Flcf}^E}F>mԶn;ȶ)  b1 s]ߗ7ߵ5tD"F#*rGoږOD"=w>i]ϵ7=Wѹ:@ b hsN~ڟw< 3D"lm.5l\ϵg݃ 6#@:l>>G,:@ b>m}}޿wm F"`"F 6m[ `r=jHD"{{k{ML>i<+P"FL^#|SǷݾy/KWg9D3z ?z}>IUg9D,03>o[zw*`h?-"Rzx>JuXP}skuzA)}X? cMWADDቦ]hqjˡm*0f)ϻoyd~κ讟M0}B(:]Ֆ~Աy!@Ģ ׍{ >S꾺rlBM؎"Fl^ϴcEWB4mBlz Ʀt&#:ʦO{5ǟZ@?ztU'.D}ӿ}rMuS[W;|sQ~qz}FoG__pV7eF}}屧 ??=8_dj}s'=};}"&W?T|W _Dը{HS:1xzsnɟ)n~ʝr׵nOȏa"ssl?'=#xvNuѳW /eZVYl#g?qe`\SMjc;Ʒ}ooew( ~}/ Ek+}zS6m㕦[%F޻,kq*^* `Okw?#_y3 X2}`r%"}XG ;寮)?f 6l۾o\a9~Q~yf-w?#w?#?q\.hxq^A ?*~kQƀzGƭ.7耟/:6/Ku~I'#:dߝޮQU8. A>~p,w?݀:"FFhK<'p=>ܠ߳]4"?{ܽ\wz"ήW{q%c+J3`"(#p݇lmٌX:ӐM?7 bg@sˋ o:}|g9zپ01`=D|'໏]?>b1XPwt}޶~ElzU@ bי{M;>l}׿y!6#@Ă ]]W7-h{Sow=/u=@ b ]k{^ؖoZ12O3D"֙{ͷw]y {23D"l}>5`_#nV{1Xgu\jlBљ`"FlcfO&1w]l(F#k{x噖o{<3D"F#jbumE0|?zC#u6|4ݿk$ڎ /jVg@1D3ж\-gt&#@Ă \mGk;p(  b1D"F#WE7j)@+rZe7,c+ j|~hghJ{RL>FCzl̬jf^TXn33dz4O>9>55Դ|+DDL=1r])[Kы 5~Su+@2+#@=+ J6S>ygmYծR4+pS>-˩8(KE=wxH2Mv3ɬ~_S.̀]oi9Ujc%S^wKf|볭 Wuņw+7y|cZ|~D}W>W kI/0@}KOzzm?(8LU2UFE~nRݽ_NX7dFlWJ<,Uf[)X l8Uc"{b3 pr6`[V*VS3:Y1<[5jj+22PjjE})Eҍ`.ќ7Cyrcf@(Pim@\ߢWW/LFqٿ>"^xؘK6 5l;IUlL+QJ6ʞahn$}{Zd!WanZ'T=b5a'_a iLJczGnV; "NQ2L)3M!r'@YZK>*rNˇ}U4]pRL:Xk@ b1DS*1Dחԩ0IENDB`kcp-go-5.6.1/entropy.go000066400000000000000000000017531374022726700147520ustar00rootroot00000000000000package kcp import ( "crypto/aes" "crypto/cipher" "crypto/md5" "crypto/rand" "io" ) // Entropy defines a entropy source type Entropy interface { Init() Fill(nonce []byte) } // nonceMD5 nonce generator for packet header type nonceMD5 struct { seed [md5.Size]byte } func (n *nonceMD5) Init() { /*nothing required*/ } func (n *nonceMD5) Fill(nonce []byte) { if n.seed[0] == 0 { // entropy update io.ReadFull(rand.Reader, n.seed[:]) } n.seed = md5.Sum(n.seed[:]) copy(nonce, n.seed[:]) } // nonceAES128 nonce generator for packet headers type nonceAES128 struct { seed [aes.BlockSize]byte block cipher.Block } func (n *nonceAES128) Init() { var key [16]byte //aes-128 io.ReadFull(rand.Reader, key[:]) io.ReadFull(rand.Reader, n.seed[:]) block, _ := aes.NewCipher(key[:]) n.block = block } func (n *nonceAES128) Fill(nonce []byte) { if n.seed[0] == 0 { // entropy update io.ReadFull(rand.Reader, n.seed[:]) } n.block.Encrypt(n.seed[:], n.seed[:]) copy(nonce, n.seed[:]) } kcp-go-5.6.1/examples/000077500000000000000000000000001374022726700145335ustar00rootroot00000000000000kcp-go-5.6.1/examples/echo.go000066400000000000000000000030071374022726700160000ustar00rootroot00000000000000package main import ( "crypto/sha1" "io" "log" "time" "github.com/xtaci/kcp-go/v5" "golang.org/x/crypto/pbkdf2" ) func main() { key := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New) block, _ := kcp.NewAESBlockCrypt(key) if listener, err := kcp.ListenWithOptions("127.0.0.1:12345", block, 10, 3); err == nil { // spin-up the client go client() for { s, err := listener.AcceptKCP() if err != nil { log.Fatal(err) } go handleEcho(s) } } else { log.Fatal(err) } } // handleEcho send back everything it received func handleEcho(conn *kcp.UDPSession) { buf := make([]byte, 4096) for { n, err := conn.Read(buf) if err != nil { log.Println(err) return } n, err = conn.Write(buf[:n]) if err != nil { log.Println(err) return } } } func client() { key := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New) block, _ := kcp.NewAESBlockCrypt(key) // wait for server to become ready time.Sleep(time.Second) // dial to the echo server if sess, err := kcp.DialWithOptions("127.0.0.1:12345", block, 10, 3); err == nil { for { data := time.Now().String() buf := make([]byte, len(data)) log.Println("sent:", data) if _, err := sess.Write([]byte(data)); err == nil { // read back the data if _, err := io.ReadFull(sess, buf); err == nil { log.Println("recv:", string(buf)) } else { log.Fatal(err) } } else { log.Fatal(err) } time.Sleep(time.Second) } } else { log.Fatal(err) } } kcp-go-5.6.1/fec.go000066400000000000000000000230421374022726700140020ustar00rootroot00000000000000package kcp import ( "encoding/binary" "sync/atomic" "github.com/klauspost/reedsolomon" ) const ( fecHeaderSize = 6 fecHeaderSizePlus2 = fecHeaderSize + 2 // plus 2B data size typeData = 0xf1 typeParity = 0xf2 fecExpire = 60000 rxFECMulti = 3 // FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory ) // fecPacket is a decoded FEC packet type fecPacket []byte func (bts fecPacket) seqid() uint32 { return binary.LittleEndian.Uint32(bts) } func (bts fecPacket) flag() uint16 { return binary.LittleEndian.Uint16(bts[4:]) } func (bts fecPacket) data() []byte { return bts[6:] } // fecElement has auxcilliary time field type fecElement struct { fecPacket ts uint32 } // fecDecoder for decoding incoming packets type fecDecoder struct { rxlimit int // queue size limit dataShards int parityShards int shardSize int rx []fecElement // ordered receive queue // caches decodeCache [][]byte flagCache []bool // zeros zeros []byte // RS decoder codec reedsolomon.Encoder // auto tune fec parameter autoTune autoTune } func newFECDecoder(dataShards, parityShards int) *fecDecoder { if dataShards <= 0 || parityShards <= 0 { return nil } dec := new(fecDecoder) dec.dataShards = dataShards dec.parityShards = parityShards dec.shardSize = dataShards + parityShards dec.rxlimit = rxFECMulti * dec.shardSize codec, err := reedsolomon.New(dataShards, parityShards) if err != nil { return nil } dec.codec = codec dec.decodeCache = make([][]byte, dec.shardSize) dec.flagCache = make([]bool, dec.shardSize) dec.zeros = make([]byte, mtuLimit) return dec } // decode a fec packet func (dec *fecDecoder) decode(in fecPacket) (recovered [][]byte) { // sample to auto FEC tuner if in.flag() == typeData { dec.autoTune.Sample(true, in.seqid()) } else { dec.autoTune.Sample(false, in.seqid()) } // check if FEC parameters is out of sync var shouldTune bool if int(in.seqid())%dec.shardSize < dec.dataShards { if in.flag() != typeData { // expect typeData shouldTune = true } } else { if in.flag() != typeParity { shouldTune = true } } if shouldTune { autoDS := dec.autoTune.FindPeriod(true) autoPS := dec.autoTune.FindPeriod(false) // edges found, we can tune parameters now if autoDS > 0 && autoPS > 0 && autoDS < 256 && autoPS < 256 { // and make sure it's different if autoDS != dec.dataShards || autoPS != dec.parityShards { dec.dataShards = autoDS dec.parityShards = autoPS dec.shardSize = autoDS + autoPS dec.rxlimit = rxFECMulti * dec.shardSize codec, err := reedsolomon.New(autoDS, autoPS) if err != nil { return nil } dec.codec = codec dec.decodeCache = make([][]byte, dec.shardSize) dec.flagCache = make([]bool, dec.shardSize) //log.Println("autotune to :", dec.dataShards, dec.parityShards) } } } // insertion n := len(dec.rx) - 1 insertIdx := 0 for i := n; i >= 0; i-- { if in.seqid() == dec.rx[i].seqid() { // de-duplicate return nil } else if _itimediff(in.seqid(), dec.rx[i].seqid()) > 0 { // insertion insertIdx = i + 1 break } } // make a copy pkt := fecPacket(xmitBuf.Get().([]byte)[:len(in)]) copy(pkt, in) elem := fecElement{pkt, currentMs()} // insert into ordered rx queue if insertIdx == n+1 { dec.rx = append(dec.rx, elem) } else { dec.rx = append(dec.rx, fecElement{}) copy(dec.rx[insertIdx+1:], dec.rx[insertIdx:]) // shift right dec.rx[insertIdx] = elem } // shard range for current packet shardBegin := pkt.seqid() - pkt.seqid()%uint32(dec.shardSize) shardEnd := shardBegin + uint32(dec.shardSize) - 1 // max search range in ordered queue for current shard searchBegin := insertIdx - int(pkt.seqid()%uint32(dec.shardSize)) if searchBegin < 0 { searchBegin = 0 } searchEnd := searchBegin + dec.shardSize - 1 if searchEnd >= len(dec.rx) { searchEnd = len(dec.rx) - 1 } // re-construct datashards if searchEnd-searchBegin+1 >= dec.dataShards { var numshard, numDataShard, first, maxlen int // zero caches shards := dec.decodeCache shardsflag := dec.flagCache for k := range dec.decodeCache { shards[k] = nil shardsflag[k] = false } // shard assembly for i := searchBegin; i <= searchEnd; i++ { seqid := dec.rx[i].seqid() if _itimediff(seqid, shardEnd) > 0 { break } else if _itimediff(seqid, shardBegin) >= 0 { shards[seqid%uint32(dec.shardSize)] = dec.rx[i].data() shardsflag[seqid%uint32(dec.shardSize)] = true numshard++ if dec.rx[i].flag() == typeData { numDataShard++ } if numshard == 1 { first = i } if len(dec.rx[i].data()) > maxlen { maxlen = len(dec.rx[i].data()) } } } if numDataShard == dec.dataShards { // case 1: no loss on data shards dec.rx = dec.freeRange(first, numshard, dec.rx) } else if numshard >= dec.dataShards { // case 2: loss on data shards, but it's recoverable from parity shards for k := range shards { if shards[k] != nil { dlen := len(shards[k]) shards[k] = shards[k][:maxlen] copy(shards[k][dlen:], dec.zeros) } else if k < dec.dataShards { shards[k] = xmitBuf.Get().([]byte)[:0] } } if err := dec.codec.ReconstructData(shards); err == nil { for k := range shards[:dec.dataShards] { if !shardsflag[k] { // recovered data should be recycled recovered = append(recovered, shards[k]) } } } dec.rx = dec.freeRange(first, numshard, dec.rx) } } // keep rxlimit if len(dec.rx) > dec.rxlimit { if dec.rx[0].flag() == typeData { // track the unrecoverable data atomic.AddUint64(&DefaultSnmp.FECShortShards, 1) } dec.rx = dec.freeRange(0, 1, dec.rx) } // timeout policy current := currentMs() numExpired := 0 for k := range dec.rx { if _itimediff(current, dec.rx[k].ts) > fecExpire { numExpired++ continue } break } if numExpired > 0 { dec.rx = dec.freeRange(0, numExpired, dec.rx) } return } // free a range of fecPacket func (dec *fecDecoder) freeRange(first, n int, q []fecElement) []fecElement { for i := first; i < first+n; i++ { // recycle buffer xmitBuf.Put([]byte(q[i].fecPacket)) } if first == 0 && n < cap(q)/2 { return q[n:] } copy(q[first:], q[first+n:]) return q[:len(q)-n] } // release all segments back to xmitBuf func (dec *fecDecoder) release() { if n := len(dec.rx); n > 0 { dec.rx = dec.freeRange(0, n, dec.rx) } } type ( // fecEncoder for encoding outgoing packets fecEncoder struct { dataShards int parityShards int shardSize int paws uint32 // Protect Against Wrapped Sequence numbers next uint32 // next seqid shardCount int // count the number of datashards collected maxSize int // track maximum data length in datashard headerOffset int // FEC header offset payloadOffset int // FEC payload offset // caches shardCache [][]byte encodeCache [][]byte // zeros zeros []byte // RS encoder codec reedsolomon.Encoder } ) func newFECEncoder(dataShards, parityShards, offset int) *fecEncoder { if dataShards <= 0 || parityShards <= 0 { return nil } enc := new(fecEncoder) enc.dataShards = dataShards enc.parityShards = parityShards enc.shardSize = dataShards + parityShards enc.paws = 0xffffffff / uint32(enc.shardSize) * uint32(enc.shardSize) enc.headerOffset = offset enc.payloadOffset = enc.headerOffset + fecHeaderSize codec, err := reedsolomon.New(dataShards, parityShards) if err != nil { return nil } enc.codec = codec // caches enc.encodeCache = make([][]byte, enc.shardSize) enc.shardCache = make([][]byte, enc.shardSize) for k := range enc.shardCache { enc.shardCache[k] = make([]byte, mtuLimit) } enc.zeros = make([]byte, mtuLimit) return enc } // encodes the packet, outputs parity shards if we have collected quorum datashards // notice: the contents of 'ps' will be re-written in successive calling func (enc *fecEncoder) encode(b []byte) (ps [][]byte) { // The header format: // | FEC SEQID(4B) | FEC TYPE(2B) | SIZE (2B) | PAYLOAD(SIZE-2) | // |<-headerOffset |<-payloadOffset enc.markData(b[enc.headerOffset:]) binary.LittleEndian.PutUint16(b[enc.payloadOffset:], uint16(len(b[enc.payloadOffset:]))) // copy data from payloadOffset to fec shard cache sz := len(b) enc.shardCache[enc.shardCount] = enc.shardCache[enc.shardCount][:sz] copy(enc.shardCache[enc.shardCount][enc.payloadOffset:], b[enc.payloadOffset:]) enc.shardCount++ // track max datashard length if sz > enc.maxSize { enc.maxSize = sz } // Generation of Reed-Solomon Erasure Code if enc.shardCount == enc.dataShards { // fill '0' into the tail of each datashard for i := 0; i < enc.dataShards; i++ { shard := enc.shardCache[i] slen := len(shard) copy(shard[slen:enc.maxSize], enc.zeros) } // construct equal-sized slice with stripped header cache := enc.encodeCache for k := range cache { cache[k] = enc.shardCache[k][enc.payloadOffset:enc.maxSize] } // encoding if err := enc.codec.Encode(cache); err == nil { ps = enc.shardCache[enc.dataShards:] for k := range ps { enc.markParity(ps[k][enc.headerOffset:]) ps[k] = ps[k][:enc.maxSize] } } // counters resetting enc.shardCount = 0 enc.maxSize = 0 } return } func (enc *fecEncoder) markData(data []byte) { binary.LittleEndian.PutUint32(data, enc.next) binary.LittleEndian.PutUint16(data[4:], typeData) enc.next++ } func (enc *fecEncoder) markParity(data []byte) { binary.LittleEndian.PutUint32(data, enc.next) binary.LittleEndian.PutUint16(data[4:], typeParity) // sequence wrap will only happen at parity shard enc.next = (enc.next + 1) % enc.paws } kcp-go-5.6.1/fec_test.go000066400000000000000000000016271374022726700150460ustar00rootroot00000000000000package kcp import ( "encoding/binary" "math/rand" "testing" ) func BenchmarkFECDecode(b *testing.B) { const dataSize = 10 const paritySize = 3 const payLoad = 1500 decoder := newFECDecoder(dataSize, paritySize) b.ReportAllocs() b.SetBytes(payLoad) for i := 0; i < b.N; i++ { if rand.Int()%(dataSize+paritySize) == 0 { // random loss continue } pkt := make([]byte, payLoad) binary.LittleEndian.PutUint32(pkt, uint32(i)) if i%(dataSize+paritySize) >= dataSize { binary.LittleEndian.PutUint16(pkt[4:], typeParity) } else { binary.LittleEndian.PutUint16(pkt[4:], typeData) } decoder.decode(pkt) } } func BenchmarkFECEncode(b *testing.B) { const dataSize = 10 const paritySize = 3 const payLoad = 1500 b.ReportAllocs() b.SetBytes(payLoad) encoder := newFECEncoder(dataSize, paritySize, 0) for i := 0; i < b.N; i++ { data := make([]byte, payLoad) encoder.encode(data) } } kcp-go-5.6.1/flame.png000066400000000000000000001574661374022726700145320ustar00rootroot00000000000000PNG  IHDR PLTEQwMYQ޽\sLPUnK߹ZUT޿]\ ~N쯇`~ wsȱZWĨ̶uL :jDO3pfH,쵑neAg2!WrIH/}=(K%/Z7D+q7$w:&|J+pH3lF깊j=A PzFd9?'Z;Q2H#\-V7a?S0sJ6 Ǻb0$ l4".[5PW+NM2nHl>Z9C(P'?)M/F.a:"  D!K1(]<" ՀI@*P4αupwG)MV4݆LtC`6_>g;hBR6p?pAX9ϽϹƭkbS'~H( ۀKsAY2R/mD&NtE(FN-xD^=<"pC'r>g=#˿µʊ찈쭂鵁fl@%S8c@Z4kIrN*ׄJ ǥCzxqa`FE7JܕPm?_3U1 M,bC$V;uCb7ԐNL@ޜS^7ٵթÙzjdzHhFdDcB^@d6ѮU|i3ֶX;1}=Z=lZ,ua0v9k:1(ʊJȦR_P'yANʪ{S-}CAUG#n6︣М龓̒I= IDATx10Ea; dTt(Q!G4 i4Y9_aNp KfXM!U!*A` JDX%"VnQe bA` J#mtk()|u+<.amH#ȾԟRuV BC^EzS7ڮ59ػt8k4g-&]M~RݴIo {kTVۗA9W"7AzMYϹ}F:[޽q Pm=T>)W%"n1.̱ywO-FPkʒ}>hvr9 A7lq}PRoAѾi&*16j91jral(r)aav,<Pg,)%CKH[(CAFaZXZ( ٹ ;j@sN @RA@J"HI) %$^RzFP0Klb_*}\FeKv8GqnW-X?A""H T tg\~88.{}Jh/H-lyٱATC  .Uy1 ڄ? mҪEQ}FrI{fGcΌg3o?$%u'D"EH j=I Ժ@""RI jI HnRZ)AR'Aγ\n<+Wsmz<E"H {H 9gL> #JONB[å\1`^ti:Dy$2iοlj&^)]#Jdwu]~A8yD"DP>&k\X4Emv$(Dtg CR)smtptRt cH38ᅪǭpte(;(3K !E"\LK$N:un]s Zbt5+بSKutk1 6~=Yʹt"Dm5d jp8H f K"5z+Aw(7 JY(2:W4W81(M;$pZGs $8螠!`V;*zHt蕠Ɛ_a >s)1{5sNЛi7Moyc9gBE-y:9Q} "»@ h/+8d&YW2UKO)dL+%,2dNEVX,fmdyl_0館X: 8C̤Í?/|48a ^o V;+7+;cx3˳ոKк FNrSYR){L:y<LbBKdBa~5jO$q},Nr^RL((s80MD,WIPǒ'Ľ3H$= YEarb{Ph@T !>p޳YAX:a;H`rxYLS̽> f:yβYvbNg CG ɳ3>"kYp8_ZgUJ0F4+Aq i$teoJe ?瓠 ;tBtg~ߋ :9 w\}Qp"2u5.A$?Py?5*AWŊ&+ua!c.ݔU 4XVbJCS/pKI +U@  y>W,A^QG)pDRu$*vZ)YWHP(i@̔'bUTmԌȱ|N\W$[Y rwUP7Ȏ'0jJiK>z4 tTHLW}J'TzLY.Asd .OT1__E)՝~,}\t z`: l%z* RJK.P,䩚y& [z(7vk"bUVߚ.AfW85%8:#wcke bѠ["DwVأ;hFxdTRBwRqVYSD\9Ɂ1#MyXT^LCLmz܏;T ,Ba)^d|DXQ6|i6-G:+A@iOzec奪N S)Ac[θĈFk`@or|RUJPǒQ WV$[Y S$h9[Y&,f,0=J}_@BHˀy JZ PmAEn{>uIJՐL|@oÝW#}xƞ .Au:ۄyyP@@6JZ<(1^#Sbcy$Gߚ SCh-ӶPK|s[[ʽ>< ?%AMqdd5>L<}j COg[Qj6'Al@Gx, ?+@A$H$ȩ픙C +9zN.}<?;-B3LcRFV޹$6Baϩ@ggKᒽP ㊉]\)A P{x;4R;˓'~V%q9)98V{ct2 qD ~rVTlkyh8' On`{AT`.O4Z~Ý͢+bn>'A:۰Qd,[pk93^%ABN{= ^cI r5qka5omk[S)O|IC9~4>iEZ6̯_-AfVix:EyӤbҦ݆ tYnn -R%Y\0h5x׃!5f]5Fիgq)-9,}`:<˧y:6րAVE " g%X+$$j_`] a0K$(lkɜY53/K̊Co8L9L$-#0qMb񹪜LzXrzM7WB=EJ%6;MvR_z{ 9 H$> x-{:4 ]V]8nj&A>@WN` ap2Ֆ$(Zr- MJ 3 G!Kp+͍Xğϻ&( }pm+i`ؠ)ֽW7Z Cxp&("%hذ }c&Au:1{bOcU=$A` g> }S9ftKT, ҁ`~5CT rޖ>q1&At3}|*-IPR7$6ZWE)ATJυFJ"Az*b.Ai!A.DT1' D-H1 ,24E)-$KJCS [ `UFJ Y#gGmr > "&5-ͪR%a]0BĢ"dՙsw;$(1ЊŹzhƂ e[}GVh¶ `aDiSHP[KN $(Ņ:W+ DE"AR¬!% "ACnI /0(ee5?>J53̵xKEZ B-$Ho*A e93-H104%KӼ)AS\'$V$h%8Ke,jm zD'\!X{O״*q{g&AK`h_QܙF@t@H @q)"_,C,Jj")A:mE{]%( I( hVXkG~o:*#v%/wp"W&Y>8 o[R/K>W7 k-HC>.J@L<. ::_ "6)ľH.\>ջgd'A Aj6wz-lYym_ОG%AT  6Z lWR[D![+Q&:H$a6ŝN:f]S:%A aZ;$,jR.BS, SSU`]V͹X$RٲVw5"n0! m0;-I||,8{> x`ئo"A"ﲗ[s}# \VA[րQVE*AaLQm?גI͊E"$(˞)T4Ǐtmm|r{]fZdn]:ڿ1}!hsnuN ^5 x^*[;Po*r5t-à&,%u% tH%( g12ɄFta+@^"AЊ!=tӑA| 17 %9CST `{k07}5"^$X|O6_c&6V$,n?\%fvm#\ōlѫ< [b]^eaw=aPؚOz \V G0 a R *aLQ\Q*JV3"]@4h !Aď;d\, ]% MB@d@ f DYbS$$ O.7$ NmUd$H0\]]TGM=~/8TaBB$y/܆]2/%A<sܒI-u{@ DIGt~ Į2{F3 R*uhwT8:~Oy*?$Aw򞟠y ԄD^!m;\Amqa4LI0BFb`U "4`{XaXQ||06 %A5A@C w҅͘7n0ط qy{oڸsMP *==R 5Q8">\Y ҄], Ueu-7 M W%02b{҃E%b<4U婜>W!AE!Ax ~xD/~a&AW Xfr&&>Q"IU{K%H̪]_${kܴzjptr@H裆D/*%Y )g1J{pN{}lFCS:~׶9񋝧?|ţFqoY ꚳ?>`5y9>Yl~_9໒Pڴ^7+&B|]YH?i&$AMԣht!>Bd\> B_\GqKض^~e/A>>$%\;̙y%ȗ6$dDWKUT— _| 3m 'W_| jN8E][R΢ \~$+/ڱJP7CQiE*:U,gEh& B6Ж46Mއ$$B^' -}DP$A0܈A^Mk{i5ҵAD#rDDADDа "( !҇"  rqa-[ԤZ8Fu3H%5&~B;z U̜Lz '[ֽiizwڷJAӮGUWp23B/E "" " "" DDl~}}! "@A= euK:v69#窶̭ژ6 [.]8whOΦ#9=%$ƀeXؕu'pB roP5 D(mQJ')C1f Pj}fv}Fvq%!\ :B!?k Wq%^`I`R.ϣ顡Yf21Td*tDhDf2%}*cӞZ5ĺS??!NEqCIS pQ,|37Pr$X[H{͑P߆$ Xc$Z+U>d,P cQ BA'Oт' J^y i7eTT|+~)K` I ېAI hrX%xJP=1Yt on AHrHСE1R3 !q2Iv: me%;e-a2[U,\) Uz9 llou88tN KL;W %)t~a+2Ύ"ŒY)'./%:ռI@R ']1A; Ǝp[j$?&hP/GaZ|Bdvp#7ʌWB#E}CPI|^ b@wАY[iZ~7BIf V-E\KC߼ N(ʏM<4 :/GΝ@zM-*3w*m^ ?ٵ})|gw-o%tSM x6)$h,*el>Y RzKI7rx^;&Ks)Fe11uQ8>Twѯ(6%Hh%0v)tSP}+Axt=.A޿[an ZĽ81xTiAR{tIz(M.AڪBHhuX˲o Rg<m% *@,$f, Wǵd(3%*Ay)AL7TQ׸L8 wBH W~}L:ܬ܅*p֑r9ɪ&WY% ]I+[$Hh؜GJKP`Va'tf78s貓@Hй(7oP^4u%Hp='4,9hynM.AA>O: r,E}7cEP)H< !AȂE^n[DbDZ,3zݐ5YŪIPEI%EqJwph'A܁h#>wvXXj2dS[G!C5t6sTZ\~v k)K*r&@z8mf%ZHvXy+ xfW*I^DaG;b0PBMNʖ}m_K5fGALH r]öĜ$h x[&&J<s kLcB~y&'gdy, GyY5"A9|亝=h> zt$'q /2)2tMC%蛳Hm`Pɋ(/W ZI<bTfY J3K̞QLq { RD~-40xM z6l%( ILc["oXJ,PTRAJK+r=9^𿓠WV~"~`kW?.јT?cJrAy _e"$kNM[ K))ΰ#  fK@,~!A2IV11nR>.Ať 944ЀOO۴px[XU/As67]X?m%(B Kuxkk}Cj*h| ho z $%JQ<8IB%(oZHJ\=*AQhAVKx{(U'D);VhO"NbJ.I-eƆRFYpVRb"}9{ Z0|M1s,Ha!eϩ> ?)I܁.-=~p繭#tVU}}Eez/qt14S߿n2_i q#"kkYW^YێJ} mv zl}N5 Aw;c ]:۫4fZ=x xU >([۳륜XZ<_u=RD+t0j~=Hc=A @1!ApN Jr'OGAB4I2}CvG`lyKP<%<hgh/LJ < H ^0[E: P*W2/h,f'A~TXp%ȥ5q1@y [G$NU@qGy=?1e^w?WŸo cGQAFK9,Avt8xwm9$W ͑Яׯ]{up3iasg Jj<5 XCjH7PH G&ikF10"0M$Aܣ$KD{=Sz=>g̹ywij)6e< &2NN6%fʋaWà>x߄X.A0 Nn4T(0)AՎ{V Ul1{ L{#1 m4RXyf+AA A2) I %JȚ-йI|xk#A$ZJKkb/Au pvNڳX$H#E4%8 z>Yg z2dqxD_`ȗHUElH5)q YND$H|RKg#,Asf_+AE $(#wap$h"F;rQ;?SM#ʤgYi! oN3Nz^14XjD1BE(Dnt\N'v;0cq`"A3LaD!24eG%Ț-+Nq,$G's%ȥ5H#GH|+fQSf AO{K=T\U$ɿ"AN||}摠kx#޳HXO C j|;zJӶ="V|On\rEU [Qi7YuLЪm T_v\P%nvR${B胖z͸{Kq@G/ 䙕T磃[+r/é!Y(ջ^ SJuyidOtX(х$4ǚ-Ҋ_g93\\4RعwWq$ѻ,Xƣc_-*N\]|WxF=9ۡ lϧR:s$MT5aߍ (Ecoo<Scكջ>hݫW>i_w$ٓiiR ]H \deKi) #']syу}٩/UEVvsKP&`#=Ӫ1)3WI+"A\ ` g]Y.WL\ r%\ r%0SCήJĕ [ZUŇHmM+(WfR0r!Ii- [\XmX(5#605NO% 5E%KeEA @3 ?%_K, h"("b>W  j7tls|簕6)PZ??ǻE6Ʊ9Ean4I2a'[æa!oUscSg9lTDj" "F" ""@nAK`qڳ aԚ*dPu"3Lα_@˜7/@,LpwXQW}ZvCh4M)_rH(((((EiKAA=7@ 蔣yeK5b+ez4<|ÞdKtu}oQdAnI-d*gҖdeAAgW鷫{U xȯ׆t~:LA`8gA S2Vz$2˜@%OlùbG2WQFP$ ұAs~.65'dZo)#lʖT֞Ab3EnIiȳ=3"~#S0*B: I5;"HFP㧉*΀֍[L\U N\'%gX # `Jms} ABx#'xwjAx΢nс= pe_u^;4x:E8҄!""H^U6>!e=A7]TAiR޹qEq\3zb"oFd01pa0;F=AtL35J4f S5{Lrֺi%wQB 3 j:m2YUJ=oNO/gD5'ˉM1^e2Nz&Pb;W-q-]t$t6ݣzWdq3=[@P>`XDg-DDCc3wv;pqNALxҷԹΓkɶ%GDX`(&qښ jq9?wk[ȸo)5w:}s9;'#*U)e7&㑩Saߌځ/":s΂ t.&29oPtWTп r#Jli1 nf_ɞ\hNdR S/+GT Of7T,n'' [qy6DzA'L/>{q+1cj4tw-#[HClRV:P7oJP iE=]ӻ`k?{C.m*Bz]ۤJHdd6ѓݕNzNb';;o^}am L  sqj , ( ;D=/  SqBh!#ixD ~ +ZT uQ=jS%etQf1eA wmG8NUmHj4 .ZeQ4R6)Z%xVS?/>p&~kw 'bkjvm#e,‹D(B' \uvi\ :V G6 ݕ^QAC(A@blA(/,'ҠBJyT\ ZIs7i&fv!p<8&|Jl$o @!ijVB\ia+2ث=.Ng =@bLPPprG4idБ,J!$dcU=|)A OQtB1 y;Cc?-}rqXc}>d 9HyV@M!܀2R7? I;1GOF)&؜]Pm 3qg1%]I2شՁjjCBʯCZ4KRcwڬ UBP#&#AN{AP"Oo%+p 6(QZݝz?^q9 i+},AN 5#|`cA{{Xgi&etR} x ůR4:~S#SbH SJG˄ %)Y+|s)!h̵?[^ѦtZ]{k^(>3b9ΟIe`tIy~Efwʓ:NMk`4}. d3,,j_2ǀu!'p2n1GMHub# ]΍[n\ A#A~>!֖CCDK&U)@QK:Q4Yۘ@ЄmbǽݿS'nM5!EAPn@Ю^[ooY lF$ɒ!e%?w| L:1Pq`ɐ- 1@PF@nA"E%0ph%G~uIQ^3!=KTH~2rhpSx #E3Oj&t],aG/`/J A71=*)`N{΀^^B(S AFy|p;Q iHlMa%XH^ An)c1z5TDI@`iZ <밿RX2s<9}>Y-Y0kmA7A=( >Ylcz`A7A^<~s?]]5:W,>==ubRت]sAU69΀Pּ28i` Sifb{SRҦeiXA LpH X$M_{×lMBA?MTC0Jz` HBP^&0[6KѸ )!( T)츊tAM@ H';3a .N9bE8CY͗ץ2]q[ x x A q rL6|җ@=y)%!t s|E pQx!C (UC1 Af-׃-+* ':**h*P AO5` n Rar,1SX/sac<hvB}?QK!Og߁cE:"B5 YACׇ q\)@A7AxZ&Iwޱ Gfiܪ5."YgAYLꀠ Qj*$h2*67S@[Ln} $,X&zDbW,} У""=ަ ˟oZD/T" l!ǒ5 hAv9Ćr4Ut!l\sw;`IY10K:4>! Aә|' Y-(Ni`Tp'vX[j@ zp;RbƋKh^5խVTvIHY(jTa+@:4 45ve̚l8V64&V/`\'ȳLkSMRk(!Ck:+f Wč)olkCj H"6qYPX5kM>MSu GR[v`L|-SI2;-Tw?~4lG(gl!(y e缒[rj'D 85MAe^!AQB齈~W?Y>0΍!~FʭGreH]BW |,),]HW+6>GO A7{gNqw_6j45M}P-XP@Lmkhc&U5!QxM4xPc|s3;ma)Xq>ݙٝ~;Ӯ $ڠE&AIUb0%B0F'$w vK Jj$`}$WHhǞEѴb._qPDm]nc;%s%AC6%)J : _?=SO4 $%ůPNW׮j z\sA^.G R!A䑠 vIW'qwgilׁ)TAn pܬw?L{x?+A;<˩_.AUb$_:zfγă-PX|$xh bB$%U[II"L'Kb j:U~[ .| j-L{4۳ji7 T%GpS " -5֛{|,S|a,UjUܬ.R-&<!KH<;# +Z)Anf)ќ $3)A-O:˶s㚐 bl~7J1{zkRcV5E)A6_;!A|sJU{ZZhQpڢ*Yd_VDv)/l$-M()D$E+%Hܒwz:w w ZuP&$D7GOJЇi JuyN)kMԲ6wrd L8ڒPxPRed ^5'@Z }}B,}zUL$66M<+dJ U16$}")3YZ}9N"q"brD4]gW"I)%'-yر팆;?xyy_"5*+Ev.:r.Vۚtмѭ1OtSjR2y9vl'Fflm!H@4ߗgP4?,MԒ# @)AHU<+kTE5+J@JP*@[MVJHРtTkO,œ(.% %IPbS؞WHviRA?ΧH *uKPrU>UN XpRR]%Uh_֒Iɰ*%(q)A$A>glx *)A{CJ|H H?%Pn͹*J $% ɑFJБLURI ?"%Hrt%h0)AI$I19sJ! 9J,%!H H$2AJe/t׉/^N<$Iy>S =Ury2K?914ϡ؀ڕᘳv8F /02[޽jI8sO|ԋ{;؁]xj~>=j;5pة_ϿQy癖qƉ/|0eK<&TFH !%l$%HJ )A!%H"%HJ )AR$R$RI $%HJDJDJ )ARI H H $%HJ}P_{Ifp7G,#'G(B>O)A .WZ:*]1v Z"R#vFs %dZ4Mv5?3tRUsR\uxp%()ARZ"T΍SsY ~fB,"#k>QQ~=O[p14{ܞ3҉AU,j dT}"::’::V=a0MKN6% mӠ"8kk^5!NMf8ս`qw0z*AAܠ1C\j~`˳Ge=q8d̶l\dIp$ ЖXcj. `bc\%(̰RaE._xuL dx-= DLX٧uc/ \ Z\"A-`C)!@$%HJP>68CtT|´5>5WIWvzw5Ŷ0~{$7|$687|3v8*S j^jCZ. օ> j &s- ;m'Anq@ ,-A_Z* '%]{(CSJL9AR$A5RQC xYPF$@6t Zg%z%,XQ6lg/4iYw$pCJz/ Xul7UQwXM e@ -`ͭ43@u$ebWGXa W >+yX 91ZJJts볛6s/ڑw6ޫz5En$csS(TD  (Fx 1`+'S<O}$rmCdD9sf3$,jCY$V#!]͑8I^+.$GGj֟2SsV]UUC%ښq]I>35o4NMVU)L*d/{ViRj K 3 Fc7ÄJ< 4eL=+ANH:]Xj͊y&ÇFShpӴQˤyb{o&A4hd 2,ǀULVڷtX[o#/L(D5&:e׬ \gTLFR$H3.p5"$A`!(m@B<I>m - DBՀ?$EJP$c9 5S7ւ @$HtQ9˕'fx0[ pX 84}J ^?xDGA$j\M@f "!٤y=#lNM@-@ [eA@[sQK8zZgڵ]o1 :7RfS*5ܧc0ZZUO`Q+0!vl)$V ka= uh9YXp,c-l m"˟1iĊ^A'Aj#嚔-H88残 B>9u@,ɉ/uY$(Qe0$5R[Yx{|"j8vI (cYAm*:±0rݘ$ZtJ1ޗM_/*V D A m]3umWz )ĥG+j,(|I*0Ҷ śB0"0zy+HmܿQA|P֎ٶCH_e9Q!(h1BA Ajn֬B+:t~ Am&cL^`N\4F얹>QϮsȪ070u2':h=T'!( ?RԷ]t&T闸a׸<2y =䀠Cӓp0 v[uka6[Fr[H4}=CTzk N7#&Ï'~$@$^>z:j>%>Z @hީU{Bc֝"ؤ`̲Uh>WQALW[pчk]> :Wc)R5G jiWUA)`/%AXBL ;pw*oARI(* aV(HDw8wR'#9OP|R A¤N>.^%n=BUw A:l9մ). jm#:&]0Qt`O/v8{zyAmTpVM5rDGY & A:S\so=!\rC].O{6iRq_;hSWA@?/ ~y{_U9!hPn{J>7Ad4Яzf>R (PF˔da=Uht rMҐ {z9u*z{g4:󑸎C `>#! 3z +@з@ )sRT)2:V< ,_q0-h j^0hcO;SbgńӯTAX?F&F)+X-OtŰj6v9*f坦 v|El[}4mHQcFi8dXl,ĖӏFFT!8m5f~1Jݺ",A A=ۺXxL.!45zUtjF'#5/JC $& opՃO/,|"}o|ŬE]ᄲ4xe=4zS;ޣ к A AS9L!ZtQx h^gf2Y5[LA;)橅0 ]6Mva|}A- Sg eO@]\Cj@JTV" r(2 نԡ80B[oxBy 1 q A9 () R~ *p-oQBQYuS48E> -lٴ!hBl1Ey [M@t S)UTUu{/Ix Y뷨hs?AhyhOS#?PA|t A-(2ߏRGK濣dz ҴaP}] ABFLcp@ / d40zڭ= w"Sc[IW^눉D~qvA-=F$ ”j{RPWMt2˘*B:C6(z==!Hg,CV%A rN<;1"CpQ?(a$zhg|(#%ŒcFBQכ3 2Fj`k{dJq&r2pfo4? _|_@ůh "ۘALZUZ]g*WZyh hB6e _n֡K*U-ک"7Y0Ģ}$ {xk<U6#R % K0"[#=M. i]e|Rs %0pB{ 9AT~* )7S~m(7xBP/ 9kfپ AQAzRzXy H!W۶w) X΄*{vN%mN]Gn,aS5q/A$˽!hB. (ȍD}5 #(%`D:7xJ! !-弰5zcM K_ kq},,@o~| '+0Gt`aՂY!!Ed߂ zWF]UZ>ݧnRnA6 =d. 'AZ=AC a7cH` 8XAWWU8DLr|ZEuF YKk 444%K@|9Pφ$XH8S> [NpA2PsKq*m֩&<2$29&,go2@+p!hn Srx{ܶcN"d*E T/ Hr4Z :y: /bz2 ;!AofWU:pX< z,!Cޏ_,~A鋟_2k|.u;V{/>w;=`ŨO7߳Y9#]/rha_\?̽J M܊yqc+![z`"p˨J.']4^-K( T- -Ifo߹"%^ A ]gU(x'әe[s].ݽcwfp{gKPnrQG7Jz]hÎU')P&:-W-&ꭽEYo8 o}'ZF_VT]|J+K*W!ȝ"V 9"5CNA0 H*(e? 'TA;K!Ȼ"U^ٻ&fФX]EoERh"ƨ!B|A餢X'7œDQ<9$Jlfvyz݄.#VnR5K?ZKYnȋ:~7XX Jjo+[z+A  4ݘ{?p:Em:Uk5R. kq ug @ cr[vsMo'ۮz3kWVr{(?È&zT%gJ9-aa嶚;T;VL<-^҉Qlie)-FPA (  @A@@"D  R 2fƾfb};pyW .`T 9<#Ne}ܶ=6@ !@PNe ~1ɪ9wI^9vN鑬w|aT:)o?a s"ݘsؙ`og[#s؉{%^?9Ha~#ќYCYLazcc/sJM YA  2AS_ A  DAS4(@A w.=m\aF+,ƒ -_8F`m)t`@ݷBIF;$VUnn;9s<(UsĒ7%h90w|KQM%ȖkKPKl %蝖`ʙO>jMvnOb `wT GuvN XWK>VujS4K pKm÷ LJ( bMKNPbB|tr_:cX!Xbb Noܘ1 21!@fd:ydHP>ǀUbYmdK-AT>PW~W7E g##1y~YJ#@Ύ#*h#|+Cp7U~] >8*ʵE+ODQq-j|3!qWOﭮ<QӧgKPʟLo!>fk٥Չ'n}9!wXx Dtv35 c Zy`^ȗ5`z,4V2P D7eC!?=09x`$AYG\ ;*$8+-JP ?u@< p4dwX| Z!Lh`%0ƤKfagU=jKkaJʥn^ " Hʁ3Vk A,sRa03%H l#/wXQؒ@z(OAˬhi.jMr"I0.fYZх-Aw]y`L9A8m qPK)o;BI$+ ML/ANseu)AE>\)+ $ <({_)ƇNQcxnG\3u| (I@2!H_5V>`W|W24#TP0`TQPÒ\pyyvv}t&A:LfS@XłDh Jɐ `6& .ՑٌiHPD^"A)^ Nofې}$+FEq(؆ܓh@25?.*M 4%В)X j'eqlIQ1\@*A@ZHP:L[Nȩ ԅHx7u>᰻.A"/Hyn0 lBd-AoK~O@闟[ Aec U1uO)$^YHС@kn+JӜ@z_O,-C]*m5,8 ##w mE2^1^RpY0.Лj C: :^ |AS ܯ.A,SCP _̉0 e)m=A9JMId7,E<BEƀ c:My 6wFg2/$SMx !s A TMy(\8A'0O1cIު۵v%7+.+> 7-A ؂ ya-AoM>c߱;_#OV)$VӉX S"_VU`L:ILҙ-sSi^UQ/K0Lqvs}sIM3 $P?SȮtZ!ฉ)a2)YU86 '()^)5 KcH@\bL!#ӆHPcJ&K%zI0 ݴ.Aj:ќ2V 25Ǿ8׺x5EVz'Γe[%(aJcӯaB/3IBt%HKP?y5JP7-A=HPPm z_a/Ar/5٢8:D<ʹ^'h*A(;eT2sM!_q4T/ \&tfIH-A.=JP `% RM$(t4Y&kzH#^) ~Ɛ^-D%N7 buڐ U F벗49B2c2;%HFxpsjz9>g }j-?NEkkL1(jZGLv@d[E9— H$8}5 T%NH8v:1 d'nKT,Kc]TzHPؖwD7[.p*Xbє `Vͽ%Aj*AbSf: T-4|-$nN^L "vN@WKHtW͉wz4h[OHÙEQ(>eZ,o*ASy6,EMj}^P]Ě?%(ftit̛D)W\JG7O7WO(0oxӚGSKN'Q|YcCV-Aw\4'3F Ґa q7JP{'$Kz^"+`ljA=OQp |H>"V{גNt6#`+`~eh9V \t|M zk &lF,pSm=A |LPl(HPL$% FPB߆em 70Ϫ'$-EnnY. Orh ^*!A%@eDeMYUMI'6Dg+閝=}%HvE@@\ ,ݰYp6J:-A|{$YkXRaˆ1:p_$^Sd }>)O g)8}Xkε$!-˻ 60oC9MH BHM}M$A{$Ŗψf"ASecWG*')44Izc7ypSLSRQs%qdޚ6 k!iu' cw^i5".17!Caf%eB: Og怼e(`J&!g4mXV M{i ZTD``4cnIt%(+I,IYS@%zȈȖ)AswE3>HC^q'A sGpe;`RU'i!~VhC_g5g@yZE9H.$y c&AB`йS8|upڋCU3vU2aꨜ.E% f}'%!AD?QQw;IG@S21Ӵ0=X5YY5 \o9 vG "1>ŗT_$mNʅEpN6EFea\ a@If9|aQ+~3 XI ١L%$KdjMsiJPu_G d7濈m%`c$H0?d e  Q PP@lB 9Iǎ\$bja>]:b^LEB~)fK] ɥREH@~YE/V%H\tXIIɥ͈'`՟ȉ5hy[Q< _~_@ohM##K{Itd$fѕ.=QE4Ƣ)A);0}I\Kz+$bH=ǿH y|]2-x&faşS/A(8L4{(#| 0o&{s4 $]b{?E}H}mo '6 KHx!FpHx/ s邆w ,$:r $A0ɑ$ɻTKN/AHH1F%AВug">ϧ7;l S$9UEHP7lҲ{ Ȭs6Zm l /7 492ՆXWāѤ)Zu3V5$覴+x`(*S]C(l6,jgs~VDjtVA6><),`W? i?:!_R"{$Hi>5q =A9}3e M6 ͇gቘȧG6[5XH]Lҵ:G=nǤHu4L\%An_a늯% 2K rCt) ";BQNvC $HG 8ψ3z4'@ NZؘ|OHo(or!~N4;l #ŶȉFhyΥ;zMtpກgS}ǎFvsMO7*Dz}·VmeH*R;cu|ѰHF5&RS Xis+^bҩTZDZS '>F_QkѪkDH1[l %Ȗ [ZgxPp0+Ipo jSO [ a&]%Ȗ [l %&8q,]]sPV4KW0ܖg&N$6B36ۼ6r["Um %Jy.Aז [O [PmHnH[aA1A!hU3RnPb̮:P(d#R⢮Bz%/KK?q6T 1L uO@A  DNDP&$%@A " &A{A  ]_#HCjjOS:u]ϺNʪ.zzlhYKϐI!i8 )4 =A (H (aUoDc4qL^dIbq3g~uȣB$G{!>ujފɉwi^[ {y!SԤ%uXA ;%Nzu5Z0 iʆ;Elxc̻ߟ:|{dcv8g|HSa  0@A 5~>@K  @k1 &@A~bM  "'$H@A hrܶJ'O:=q3dU釠HLj UFrA"hsgEHMO)mFؚ\j7AR;+kf|W`1^웜4@>  0#(R||=al2hAȍ%:!ܝGض<1qUn ?=~JJI7@~VS7NAՍ#|siJu#GA$X\5*(OSB0}[x:~xRkW:?qUj^g:ԂZp<>KO}S8i醾ׅxnPK[ 7ʚ^v`\9EЗht[LHlR% b_8(E /5B! .Ap?AVzJm-[> A6~.BJ_}-vt-fGz!,Zy/Q؉Zi,}Fd&yڎ~ nf>ZSzt}i BD)a2:CTtjCѿP) t@Vң+;Ncd]%TQ䕡y#h s7CƨBN- Eyor_A St VNܯy >J`p!(JZ.]9jT`CP(%\~m`t c&\M wع#hICޒ*@`}D]AKB< ʁO7 Մ,9LaUF^Ͻ8ɹ'4*5FPj<>rWU)e)LZp2g *CyE!0qu=ԃy5q& ; zl~]c:Vbn 0w#WݏE_ ZDP; ~J-7A*Șq Lr$,uclriv8,pl%Au8ve&I.%z9ͪ ԽM: fJG P(Xv {AKC=A݉TD7LO`:z ]&# n6Q@eFa,z[лbCxp}/J7j 1WD"?ބ6$ +ӀYrD/L̿uC"(svIb̯y"(jc,*z$44"(KDt]JԵIM#I٫W1.^#ramŲ,٣$=A>(>C(ffGcʧuO׷D}tD{ dt"7*g'߁xኲ\Z ӒcO9+s썼*l Ed35=y($ 9HY{9bJIDv$䉠 |*pY9CuhuK_-*{{y׽Aʑ^܊Kn*5QG# $ݳƷD'" ">'ٸ´!&k15Q)d:0Dn^ L( Ő;U Qj_tp&&SU{UW#aA*=ay%Xi| (JGXH$jb)d65m-䉠KHUA1/m+AEH־nbcؙ-h.5`cAq16eNV.=P3}~G%#6P =oVLAKCPM6`y!)ÌpRBPs<."hr^0^i>0һ]I#?F1DН撓+AG{ ( {dW4b î꤈>V߯y#H% )T d:0J"3dԈDEϝW`ۅ/RYطl[ Ϻ遠W UZ<,=M /6.hkp&՘% 4~N,n^iԞ9zu? U<~0C/{ $ÜU v}*4 gY#H# #8Rt/ª q'+FPTG\fwZ9T!#Gr*$<!/ KEfȣ:O-8 ԇcyTuts}ٟ+w!: vOF^>@ARNDC/}pb~%A@]r\ 3^jde(quG4%hy HJ)k& tl=R1$%^s"Z=fGЫ@.fn^0CɥuF=*BHP!1A KHF^(_0,xG=!5-b}gv\mlm֏} ugTH?gq+$yUʗߜjT(tU!mQA'!*@+Ȭ h5 cj>\,&bjKSU eV?D~`ެ ?0p rOHU^"Ԅ3kmAKh)iz*FρZrɷi46L Hf$S",XO5w0TӥѾg17D~ HGǮruxE"?+9r[$^ԢP.!/{kUbQSXkwti]+qҊ:.sz#XDt-NAρוUE :yM^`o1_0WTI4^TZFΧEnжOȬ,"%+Ycn;M]LT"j+*(e:jwq ti%2A ^i (T䣒̦na砊~\Y!`rD9}Cq tnY44. VYJYOFZ* A>b^nj FDe?aE4/y3N2g'P#DB)ҙȫ+ /PӾ>B#[ pW- y y?Lsr~ Tժ>b;A]R9mSMϻp#{WQBPT#:|=A)eTZEP2aytV$z+qTܙT!be(>RFJ)lc%<ӧ]AF-&h@=A=zwwAyG27i9" "(r3)Q<}@ЈʽeQ0n?wծ]1˽`\zqodv e‰؊wF^|_i  Gǻ*օѫ<:15A# ʱ,7:-:ԛq\eDcӨӉo~-ժW~lqM#h? _&0E~:zGaS2u Ua%wa$yt f> `w۹041:4[Gn巨v=SI #hzBd=4J'hT F#‰giR#hr]yBe"b1A;ӹL1;/FFPv{WrOK'hTDJ F'ܣUلrh~Vʗi=KP kYJPJ>"$h$@ AF@ AKPX1MxQ# J84SmÈv˳[HË: s&9.+My|W`(SKTϿVg0iuCyk0MoYVО'"T0I\q]^"fFϽ8:쑞+zɌ((Af3Vm8\A A H) H$ Aay8  uA A HPg &AI H$ A gI@$ }kaW 'H@ J$8"R$ڎJB::N@O-ז #YiI,pnŸxf꟞ A; j. B!tDZ !C`1D&1\%v AuO۹>~kLS& k4U~&D"OKpZ.&Y M.WmX̍.,k,{ƀK)c4@a_2(hv6Q aZޘ_͋pY}&D"m"hpB(:C8B\$sfAj rseLrKc^J~ٶ)%B4<_kN8sB<Ψ "AKJ aZp?ދ3VY^ DrcA7]eWPtE5A g?<]xUZ(޿>NLjA BPAb },,7<478 @:?$|)(A%L.qPG]ݬ nԀ-.1/Y=95A B!Ĺ qqEP "H D1'P[l7əa2yˆNr|k ^sDo GzONq k:&7UݐE^k%KVBL?ݽnJՑ}n}N"RN E 'YP6q$GPdŁ"Dp'ch+m3c'[`)b6bݛJuvrmZ3\OwX(AÙsb\4WgXW444.%va>` >APl+kAOD!vp7#h*xg82##ԍXqOa,AۆVYN x1QLQzc\ObZje Dfrc3ʤLd"~L"+AAAAIś A|z܏4qGXxA"`#hx @coeC#> H e`D~&\zUpZuJk%hGpT(mr8 !:ثs&f,@B/+{@{d| 2ATy{ B$zhY;`+AAAAzX AOk9YD{xAj#|e%KNYE2D m" ЗZsl8PhtʧJNWmJg%4wrIuZ{ǀBP;OLJ]" D?Gy`> Yoc,[`&oU0 E[6ѕ Mrᯨe2q,%|Ƌ[N[!|3w8?!h"fQ y~l8^{nN\C: Aiո9iODN; L#fӇ*UcW(tM#@b]tv"?zt%H#H#H#hVRABВяo>DP_xM&`Y mxЀMidAV4Y4eF]lL:gDPZ+A#>7ޜ[(_-&W{k,Vtj_:+8hs?R2Բr*TD@@piiim@҇T"( Gʠe䳅B:DE>f"/Q)D2L]DPZ+A&Qʄ5D.izL/93c)@:BЄMKSdDb<\cLW4446 mA*Z7C WA_4/z .Z_}Mcp$&xdρHkt~4AExR85GqePۦh7+,ɮ[_fz8)rv@j|3JWQ0Ezդs{|ǫ?:"] ڀmT"AZO3\!?EP裡t6YPo~!uUgIN%!h+A[VA #܁5cbQb9 t 7:Z@-0) A,QmH,yE'vyo3tV~\POW4446 t҈93GᚠAV piLpdYހvPM< "%Q'2Jm%8'TMMArfM =)+.,5M";s4446!s$jiē As),` r-?p}>W7Թ~A2d jmJk%7Qa Aޭ'a6?*JItK+~zTMdaa]`_5B=[ˣilP5q95h M_[xJU 8a5V@7]tK@cnLij>w.1&KvN K8uLj@gn VKeg%p 9ĭCP*A\RAi]DCPEvg8gw]dEF뾪l|RAA߭^(7Ǔ2..4{<^-:ёa΁78mZ8HsaJFFAFK"r { nlFs qQ76 H,~3!8- ART>=чA!d2Vk3AiU`ӿW2 OA,U^I"HN6jxyI2q^<GʘJ@(<̎a!JW4440X!(  fk|0m&sIE!H G:/v/1z?st/fЕM5 AiJW~?R3J:Lvh;A AQf`8X5*K M -6܄ sR`fA1] 3hqð,Qpe/BozRD7z-EB /nC?L;/;d}6vN%Ts ZL:$^/,C%2qg B4 r$<:ޜ($A H$tҾkro+Y AH$AEd9sD6| Z!L/ H$TY 3 $AJPV QQ'uqfۍA A HPu! s &b 9 A A HPu]) &ȱEƒ A A HPFHPA AK'?'[2Ӹt()5D#AA ( b+A!A$}Xy$#99BM,a: ={aZ(0 ķwHP@ @X Ay ]7SK(UӃ"ı-ޔT9&];ֳ̔ފMHt8aHa/G9мROfZ.?.%GT#小̡xy+ŏîv>8ad5 A H$@ A?ݽnP}^}ޙa , $*nYDh\)4J#t*uh.96@)u7'lC"rD1DADEALGADDgADADDAYDtDDADPnlۗ^l۵B]v䉈 "DAD)ht=8&Z$:qk||*;W<DA# "zAo/DУ2f+Mxѹp;P0R;UU[a F}""2GAD$ds8j$(ڕOv@Wv& "(sDDAO"PxK튠@]@@~z;dAT>&ӗ>`Grp,)`]1{LS}cg{  "h׈ """)O򒻭zՁHG%E"3o)& zM./>quS*Ëm}mW0U(aDSDDAY4x20FzEjN8J4M $ Q"Y_"?"@MֻJq4=oaƨG&>/&# "ʈ;?Fct9,G(`K4Ṱ*_h> ǭ»È "h ""2"3U!(nѺD-:6m kT@>Jkh繺Ί4Wl. "zfAD6Hd6Fa+t[L u5C5,AVnj*^# DA.""r2 A""̀^jsA ǃulCPlj\{PɄ DD= "Qx/U;+pA(/11MђaPv A "zfAD6KatjL_SAM';= :UXQQE7YbWv {zB7~C5\eBPSjk{1DA$""r 5zs4N]YtG}TDZG*0]A2C $4lc_>zs#}fm{^- kE+n]AeI4eGoYphYв&DD=DADP z \8ʲneȆ_Cg)&%/ꏇz˭A5+ƪKF7l~@9:DD=DADPV\\ޮ#蝾u^O*jYoA5=~^Id$%H~R U< q^Yլ M "DADP;F\I_=\!_F[ʣTkڍ/kf wo煳^6Rv%[g@Ek "h ""AF|8_[BE "ADDeGVY}/jADK# ""RpD`ώq[1qh(&nꠋ.#p/yLL^c ~5XA  FABAA4   AAA,  vAeiuv eiD^W!f=igavKnўMjԪD]l+^uꍀo,Yp^DX`z5Gdm\^i@P H Sۍrݎ5+]G/a8,ߎkavtu1+Od{isqmC:k`Y5 ㈸;KnߴaW(3㰘Oz %qAA~   $       H  UAd׎UՆ0!k{fddAtKTp/ EbL='-Xr_ |Q AB$eߣO !H 9[M3 !H)!H _. !H !HRJ !H !HT<զ–v$;<| w AјNŇj{.!sjKM(9N{awbpmJQ6 {OV2ƔqlI$v ^& !H AB$݅ O,Ptm'^d醮#M\ ]$`5czsWI<-|DЮx$1mf6{2`A % ABt1Ov's:ZT (#@E^F]*T m>_O=Xc#ٷd5ݫ19$ AA !>e&u_yrK.|"uZS$O-=8i'p`kUvw3wG r@9zwD~sb!Hԃ$ AB}[iEv8_JpaȖ{Ŕ7aK=Ѳ9]ԷjغlZ4 `nxlVAB !HC72٧pŤhrWۮ)7ԅkIFm׈S\*/lAϛK/'!HT$ AB}yD%r 52r6ظ*#UR :#hw>3m- ABj !HAoi"9\!}kFQr26itO8J@ A^ $d]8W >!I .й]2("]K)H㺈UG9X,Q n:ݟb_s.9C_]{A @˸*afDuT%=}딤z~Yxb=p|dilfm%}l@A "($/S=7f" jMО&QY, `+*ץ#( A  @P>&ޢW43;/~:@zJe uA1{42Q2j`ya}ZwNz5@@A (܏9~&=|< #08JS #uCa?;/e$w>4D^W: >;YAu$=7F DA  A r%UZ&2⧭> A+N[Ql<;VuNv~ZAu{HG  A <jTzv&5pӬaWaoqXp_S[r6L"c^WحWYG=4+$Ժg:Wz D   AVݮ?jO}zq7YݳAuE A _#Tew  A  H=in@A@ABТZ  D  T y=ܬA A Aq  * @A  @AD  @"A N Aa?;˳t/Ӆ廛->?*~f;+{Įw.oRG'h+nl}\'\O9ҥ_`rݢ_"{'O+n6d_6oN1@%A (#TE-d㰋㰬vaם8ʙTW;Ƒ7/i_qL8~oߥqz|wn8\ sVî8N췃smqXIv@A"@A  @A E AD @*b A hk} Dف @Bg#ɭVomR   -NoTQ5@e@AAػ{ն0R1ix,/Z V"TO\AE]!`:hTґ@slEIhi?$2yc#)Gs؟ޭOAD3FADWTN"U*@h"b# "ꈠzHc%⅞.°Rn=[r;L*Ll. (BiRax)eI0È "" "B uv!g@cs%Iym6"S4r]37{ DDcADDuBT9oEnOa9(,lAS`P,.0[9ɼ<# "" "fj,rv H<" {'ֵD /FdD`^~]TfDD1cDDARװr Td ҶBKAQ7MU-{DADADP'_wJtStĀ,~H$~ x@w1F@} l6DADADP'MPfEI dJY|!; Adl[f'=B} AD ADDuB6jd@* ULdܵ00t@km[ ;w h;""!"">8¾ pic9@ڢk$}g+`&u׀GAD3DAD A_@n@"iMm>BIۢYֳ/j&DD1CDDAtmI)$M}1]fI%}.'?{x`4D1SDDAݺ͔/E#Z&+Q-$Hd>0 }o߭]Eg̎mXbADLADDuC,C~*e6 saId63p+:Ul7K$ f" "!,7:eTT%3TmBxTcw6L~f˥2AADADPd<(iʁ\ڒe"m_ b:-סas6a/nnJ渽e^fezqyڛ $DĈ 4A"bDJ 1"H %rD$A9"HAAC$ FDPA#DP"(G A"h(#DĈ 4A"bDJ 1"H %rD$A9"HAAC$ FDPA#DP"(G A"h(#DĈ 4A"bDJ 1"H %rD$A9"HAAC$ FDPA#DP"(G A"h(#DĈ 4{v0alF2`- t=_<fL# aD*JA"ˆ T#DA"(G #DPQ"(AFDP$ AE8"HA$AqD0"HU=vdy>~_m;ٍn"]3zX`WA,rpy=%ϱs y\7vftzN=*DAP"HU=~mVtnGaiqO*u}Ǐ}{XM!DEA"(G #DPQ"(AFDP$ AE8"HA$AqD0"H% aD*JA"ˆ T#DA"(G #DPQ"(AFDP$ AE8"HA$AqD0"H% aD*JA"=;I 0:nAb*rΐADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$ADP$A#4-}{.kpgqg5GӇ^A8 _uZ1l<4oٷA"ډ *=na5s;0a/ӼqquyqecbqXA"ډ JUA" JUA" JUA" JUA" JUA" wvaP@NIPIH4  :%Ai$A AtJ$H @$IAI) J S&A$A$(M$$HNIPIH4  :%Ai$A AtJ$H @$IAI) J S&A$A$(M$$HNIPIH4  :%Ai$A AtJ$H @$IAI) J S&A$A$(M$$HNIPIH4  :%Ai4(A ¨. t+miK)M#7("Hʏ7ƼHXݷczvڞ(7|yvsy9z=y21];ڿt"H h'DPZ%Vqc>8l8lO#x&Dv"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HAD"HADIAEQ@0^lFD]_"H AY"HAADPA D0%D 4Le "H AY"HAADPA D0%D 4Le "H AY"HAADPA DаTHrp_g]xSufz"g"R{uL"֜&qxGDЕAۉ ìVX<plA"hD_DA $O'A"H7u z"$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $سc ao8 M=gH.<$D$A"HI"$D$Kz|{c"H 9f9l'~AAE݈  A"Hu"$D$A"HI"$D$A"HI"$D$A"HI"$D$A"HI"$D$A"HI"$D$A"HI"$D$A"HI"$D$A"HI"$D$A"Hqg6A1H 0;LU[ZZ$A"HD"H `B LA $I"$D0I!D& DA$A"$A"HD"H `B LA $I"#賥1};.!pA"dkq;909%j%j%j%j%j%j%j%j%j%j%bώM6?c!nH"hD$J"Z%IA$V @AAD U"AD* H"hD$J"Z%IA$V @AAD U"AD* H"hD$J"Z%IA$V @AAD AFC1 w8٭Aփ\HS,I$AK,I$AK,I$AK,I$AK,I$AK,I$AK[0 *PI$I$A@I$6 r$IAPIENDB`kcp-go-5.6.1/frame.png000066400000000000000000001062461374022726700145260ustar00rootroot00000000000000PNG  IHDRj iCCPICC ProfileHWXS[R -)wH`#$BTȢkAł]Qp-,6,XXʺXʛ{9NΝoe;vNN@ OLHLb:pl('22 @}]nCk(7l$u*'DBq!>@hz9y9<Kp kJp [Kmb f@4$4GIN 'ͅ!ٳ!V&Cl]LfaY.R!E9Yyg9dgG0. v svS!nG@e>Wj/r~ 0@  qf;R_hBb8E8;JdH煌?.b%Eѡr~6Bq1RQ2L3[4faKׂceXO6ʁq7 jg(?'a}>rE?7fcją-1;]z` X+vJ:ᩴFWr˄q6vv}vX-__R/Qonc3OOKcݘ plv.Hv!ݳoܳ@e7}S0_lǀ(@~Z@spdb@" +!9`X A)X 6`'(Mvp <} ^0!!4h! b8 !QH"!D,@!HٍT!"'st#}TTEM +ꃆ1 4 E "t5Du9z B_1f`%a[`X%V5օcq"NǙ `<"|?x7>%:+;!@H#! 'wK" ~ |*vb-,C$HZ$+')&告I[HHgH^"Y@$'Br9 4<`UFaBu^a*ŌIdPR6Sj())o *(nVxV9xM&ODV'-VV:zGڸT9;/jW13duPK(:{tZuuttstc26ӧ{7af173/0 t  c k Q\R65 O1^`\m|D$dI{S3x/4B ̪̽s+oZ-\-2-[[N׭P+g+vk &ߦڦۖaf[h[oj &LjdedBF7 4@Ŏ 'ZMM1irf/.B>cdm.w\]#]W^v#-vkr~/L/&MM;Г۳ˋ˫]eXdyk+=oY?ȿĿ-@- 6`k@ Ag pBB&L^8B(54:tk00aXt)< 7 G""s#J9b(Q-Yb|c<56)M{_ߕ0!aaµDD~bC)).i_ഀiNw^< sg\=3kYʳس%&fG+ك)!)R8~M\w+=OL-K}晶>/;<3}fD̑lrvrI Spa칳;rrsrs7CDh!OsZ^96Wu`n>3y ,ܽYyŽKXJYB²w5-))bbawWWt\enRϫ8lGVn[fZZ(S-+(Y?e}憒 6x|bMMM]67l1޲v[oUVnٶr;X;jv,iA*M+y7no/TW~Q.TTU9W~ݵ#&zhcjv~W7P^ՐqrFɠƩ5)N)83x6ls=ͳO8 mC/^x|O˙˞_9yj5kuN'~wDs[u n:Nwzw͐n{wrᄌu<$<,yX˹Tw'z8=/~-zF{V\y M}}Le?UX$ y&k|<=4և]?||xg_,4~ p${d$-dKhj*o@Kgv(JT}Q²T v a-9zǰ86"JutŢ []H| o\ٝO"Dxe!Amfl6nz pHYs%%IR$@IDATx Ey$'. hQT ZT VR[5BmQj/7 Z-H/Т-@ (Iy<ᄏ{.d~wfvgf f=+LU֭!l\ ;}zSW)rBL9wT ~EdʹïP+"S~8_r+ǩ(Ȕs_9NEWD;q* "2!L* @ @("`  @ @hBZ8xA @ @"2C @ @ kM@ @ "֊@ @ &n- A2!tu4|zc(h Y,kłh Y,kłh Y,kłh Y,k׆ “o&M 5ޮ}$kiZ^`u/u_YRϥ+ʒ|.e]WT~8s) /KYW%~\ʺ¯,pR~eI凃_> > @ @($еeKZ_=)u RLKA{zje:5Dmr|0_!R+0 є_)LWJa* B4+C8 ٔ_JaW̦P*b6e|WRq)bJC *+N@ @ W @ @aK @ @d/@ @ a%`mX8 @ @x%`m>Y  @ @`X XV$@ @ 0^ XO @ @Vֆ/C @ W @ @aK @ @d/@ @ a%`mX8 @ @x%B۝sGLB}՗;Z(/ 2y{G 2evV_&oh\Lt-ܗ]Z}r2y Q/wP.s_&owA:jee.HGLB}՗;Z(/ 2y{G 2evV_&oh\Lt-ܗ]Z}r2y Q/wP.s_&owAB6L, @ @8rn&ݓ__w-I$qRZEyoߞ P'_ʒ~BBҴzҿпVGJҁe%Iпп)> vVKW d?R1IaR4yhң|?o~B ưkdR~Uh5_#*.B1,Tq_ZaȤ j F&U\WVc*O!kuE͵feJGj<_~!lٲ%iCz;]v%gGʳ Y_GJa* 4X~znCv1/,Pc$W*o{56+0~n]B~Ȕs_9NEWDX;vuݨÿ /!mX߲i盭_m_~| ӧ'@Ru}~+[wGG[|l{߃~N8ׄ=صWI͛w˰jխ ؗܞ(hI'GIԩSj姆+Fzfx4kOiHct=R};i=6v~X! M^Fٙ֟ NKUhܡ [n6eʔDZ~@#L`MB͚ה+ 7=P'5w=/kGb=ߣYP#@=>< >3/wuƍO?֎;f̘2#p]w:9ݕIe&&*/<#AW;T̞=;~u>Ak֌1q >&zgZ$2S!o_y̚fA @ @s @ @M XkO@ @ @W@ @ 4%`)\!@ @ Дx @ @@>k\p @ @@S֚ @ @s @ @M XkO@ @ ޺ѣ7Fw\ @ @ 0QlB{f\{zBPD  @ @&")mBxHp @ @@ӧ7:5ɓq @ @D ;';2Ŭ@ @ J@gy3RP# @ @ X @ @0֌W@ @ T `,B @ @ X3\!@ @ P  @ @ #`Hp @ @@*"( @ @5# @ @ X @ @0֌W@ @ T `,B @ @ X3\!@ @ P R 6_Wa=PxC__ߨ)m裏({7< e [.ˆpHm8R-[$㵍7]f"O>dݗ\?ϒ{$tx3.\;0k>}zxֳ90uKK_Ҡ?A;wnꏥ34׳[Asp=_w;Sc=¡Aײ8j˖- 6kx1`]骫 [nMܞg׿#Hx_O4wK8vna2U{/|ar_-y)SO=5|3f̰&AQGGkI_s^}|;/{^P?+CNQ6VZvc;䝠2uQI=,XrU|TU_W'j^;$O7o{ے>A UWw}V ~{q2(]N;ԮT7m.~Ȧ'\veI^7ې1uʴ=~ cK(.?<34x^f͚eQc4BcN8!~\~??;_iY(>8}ު/o_g Ò%KҨ=_>qSڨۢ>\-ݣAT7`L"7ߏdnk =XrLk,qM7%m@}޻kjuMH-w$]?'M2+5FַuߕMQ[-*ܲUcӑL8%K mޗ[⋡裏Nd[b?z͚5kA{_ %/6? R?K_/qr;4NxId׾I_R(`;S _ixV6g>.^ץm~ p饗~r/}SKۮd7~ )L[qկ+۟Z?u=.=ZjueȾ#,_⺰•yoEA-쳿̫#CuCYfg''u >٣@cii4y嗧e}EtV:lTSGAx=ܓ3^p-n\rIZ|=2{\xq,kV/ʄWIͧc׸yU>adXS}t+S}?GasR ͫZUP,-r>RA# /Kҷl9UwG]z>hU6mcmJ-S)>=ɾ2}NO%l6NP|i2ʠf/_^mN371ш.Wi(EoL>h$*2 7o޼D_KDf>*bla&??;Φ#MoZ.,^~^-s3>V]dIgWUw5~ѓ%J1E1G4Ҫ"hwi>VUiW湅W]i(G`\V b=U=VdMqZDzr3{`}8ciǑ5]K| L*gu9 43Qž M/^MVHn w_Kj5T{3I\HF^Mxh9o5lr履~:|cKkYqOt$,¨ l2 ߌ&RK!jm 4Qe~uE:K0jeAKU4y/V=iЪH_j#Z`T%.aړLK^jިj zڔЕOHg.vuDd_z'UUNW-UQ]u}IjUYH&ڄ7|s];BM Au̖+^w7'wke76>\zgDxG*p1w{,Zj&3bfB9ib =n%PT fԿkW\a5C0-S+}sE]TWKprrwjKf4c!s/u>tw婫v]Z:Go*o-cA?vV?>я(T_O:u~w:SevYC"jaF-g?Ó>?wg/KK".* WWɸ1Ek[X 5G=Ǐq(>Rup#j~Riښ4UZ͌SX[ז[<- ZUkq=W_3X\ j_l-&FONI=;j"Zb&73Z:urBLݕWO尥q\w-)/9h\Qo`7ree +yZY-C/ l9˼UjZ9Zjt/'!HMꉮQP<}^ZӳN>Qs2; 9GK||!(NGͺ۔5,Q.n[4}m'\Fu8g~K}Id__}v꟏o8LSvM.'nX_SYvkkk-dXuϲB^=e&vmG彷׊mk>lHH8NǏu.:#Ͼ?yrg<1|~`KI}]PiV1~1^֌T+[ 7u5C}Q򗿜xvs: o}URKF?W(쓱ow/4<4GķJ[uɵ5P|޳6>M&u/RuF_-x3 tQmtnKD&/eN"VK1qeIV-J@1%N/_UcfϞz0i]温GЗ>i7UIqнSjLvɮs>Fh^ -Kь˘vQ<3P]6f\ٯTfFˠ1; yKCTM_h#VJ[Іv?*PqW~}]ک>2r}}F4qH#+N݊xtg)/k&'5$Rw:I'=<|2ZoFV]KԙK]V1~O ^|><'5D5ʫih1wkf^{/d۫'O+ |y&k9jG]!'Y~ x:S lf$8 OUOub˿$|xEW_7?'[G)u+p{Ne۠eU["㙈oEqp<-?yY.z ƨ oH$h+_UyWwN͛.kY74iIeI*F}0=>,XG[}ps{Řv=[MFK m!aF-loZ5.ã7XJ80]K-nv S ,xUi]ݣl)r NmQIS6:ŗ0O/_/φmw"Q>2$LziMB뙼MoJ뿢煗$a6־WL^> d럥gF/Tȭ˕h`SOK5$A[;l[h&lh'߉gIh?Z( _-mE>X}yhe/++J.xr2qXB h&m+ӨA{T5d?VM;F哽[o"ֳTݳw) M2z^*xbCM[%-/a%+T4>R+@8욧䛅eLь0J(4uu}ի^D e_ee3+|R1a@׮3.ޗ-.q'XS/Z%XdiT5__ڕ( QX4YRN/a^x`]q||֩+Mq5$]f=xz9k7y& 8r2-/K_N0KR Z/`[TKCK6|>fv]eOyZxL[P>#|rڞeYŢ0ye4ɼQ?e_~yr~&kW=/+4)M>N--9{XRN+%Fʶ2u1O*ᆖw}ːA|ҜD0vɚ/6ߌO/U1J~46U&6,QƇ6) 34; V/rчbc&v~zNERix&0*1aA~ldY"c ?]ĽY;R_}ꚶ82~L"!CMEu0FxN6}OY[dڿg7<*m LG[t*l(/|Qcl-7KMs(qިC{x?-թaꈵC!ѩ|~+sk}, G@*$ j]MIEQ}k4m[d,7+ L8?Q4}e*.hu0m] O@c)!hzLx*ie Ni.ʦ~M)yQ>Mt&hvژ;XJge{+,0΄f~L--ʶTAn…`M@W{iFKP5;,N3{;&+X3Ҡ^dI":L=-gx[Liv?꣝ ugQX߆zqۮsu_ cl6bLa5,b[d;TIpgZlU[Bp ֌>VzohE{^SL\q'XӣTG5::^k,ٯR%t l-S7'Nқ*(xZ׬PM~~KKW/o/t:dMi6l9oB,C!`Kɓ+ y;ޒ9<xG6Xo E،6c]ҜnY:z=O_#-ءꏖp2`Z2$1V4QDl3kX GoDw-^F[]4m0LXmDZsكuk2ߎZzcu^j>ULP|_dُ+FcC0a=v RߨaB5ݍƪCT^Es.\S\Ty#"IݡT-] 17 0H[:]G@/;R+ۄښ%) U}4h.cJ0̴2W%Cm~#TЀ/kL(xx"kXhM%p+N).m/1:c9/-tofְ4 &9(no?\c(ktRj.w-+=@ y} i ٴ&oRSyFuQ˯\V+7}0X74#}ѤV~0l/@W?^.{KNU՞(hr\m(^F[]TG?~7o^pҺ1EY>|cPm_B!H[IBZO@ƽ=`%t6}KƘ(|^zmzc-%Bն`&y-Jc}NVJP&OD'\\T`fTF VߛI` 4FTJQk}NˑC{9/o%Uٳg'_Ϛv␆0cC߼ҫ,E}SuzNE~iXFżJ//yķiOO[:!I{ xr{lږ«.BǽK0`Fe^,d`ڂϵFlvꢖ~R*_&Կ(0ND-Gi8O6>Vf>:묠cjg-w#oޒZQj/m>jʶE3x t^&UovqGb5SvTcUkN4kEqƻGj;9>y-cmJ;sR%AwvU%PT>k?4O`O9{Ԍ򮪧o#5FQl_B2FM [v[Vx/oNn #0nkAiKLnv^I3Fy1Uח8m9s4Kn2JL$<y6~g;vu"a殻*,pjsF@jG}tZJ^J2Zo -ehɝ:ތꬖySvCLDj)yHZB{j -hW,zzֿ?ihڇ0E f9;jR|k_;Ii,^]}o]?;yy~(^ڭҘQY_ֿy_]ϾwXʾcidykoR5uh54Շ;KK+ #5Nׇ@3ړl?fqus1Ҫof\aBEdƞ>ő@dWhڟ5/2}&A ?%E}k6׫Oۇ=f{yvc" #0kI"_y L^(d h5_eeDhت6W<}P6/({t2["Z6V$V>w}w/RsB^geT^pyF宲Dje׬-x 2fh S6 *A F5``453F{-g¨*uI.MW*4pN .fD䪴=@JzUÖ?}Ǵ[c;HÿpEaƻ]JWڏO^Q_b?,LZeycxEnz^3>/'Kksm*|z1uEc.ض_;$o꽩y]+arf}*X}YW-_st {oY6y`w)Ÿ<<2db?яJmh;h*r`'뮻&Q}CΩݿd ߱ytj5>m JB o5L'R_'KL]y 'XԠAҜ5kV&K|^hSy!ťAڛIfRWi*S pZSj.CC`ʕ@ i5|卟ck gۯZ^}4HFKHGb6Nm}lfiI{v,\/fW4>+0Brtg)}4hJ?Vh#8"VsF+H@ڔ6;_[EC;462AP^fnKSeڍ;Sў~^cM%[o"keڌ :=WBvIfQ殉-/ЦUN ~$C5Y/y djo`hfd d-dH{*ЋJk J2vK#YmP 9V{i\4AQZjFnuW~pW1 '^+Isiկdꮖ ~4eOAhezᇧ(JU"RH6k{BVGq^lp'Ҡ}7)-.o%s,/pw:4+g%d jyY|_LL?MWh#!>iF!,_k8Ũpq/XMm+w}U'v?x6hٗFBg}u?J5f4i+Mq41gnٙjF#d(Υ^Zw/aJŒ, >cg}vFS;0A`+?@,|Zu/׿nJ\t<9? ei/X)!^G"S-vmi2Roogu>MC z53/Oc+`)m[7|Ă&BzT1&ڣ&wʡw2?ho!ȿ>MOIj2`ߟtv1dr` E 򰓟eםŽVly=o}if8k?%|[xd܏/4&>~ îfy]}?hr\sM*Ԑ'm"?>]c_>p}~G? ƥ_AzK^K\Jv3.nW/Qc%iho۲O Rn{_?,ji-S YIإA`MGhҤIj~cT ^WY«H?ACM$d2?uZ?.i& *]/MCnԧqqMP~^fdXHoB4-{K,4y:+ 4ՄԀ-$J_'9J&k[eX h(hI)mK捞4[ 6X"<^UG/f8u ~PS7*nJ^zV'>@y֔m ׷1-_[_uD} %2iU_%ANhҗTE+Px^: =s냍T.5@̛}ʻ75HZĊcKe`YKL!MdFL8;~V͇?d,F4A_}hVU_} 7hTf/=h;FVވi~L0Sޛ^SfnxSZJ5 8D îWw7Pj6H!a ?|U!ښC3{UO>9^v01~.) c+}~KU(fEcvE}:SsͩU){2\yZ4^Fs -gUA]oZU6koտ̌S]G v &.;3)]nē'⍥qSW2M˨/~J&ix{ԜII~_*Ɖ?~įJ}qRtKSϧѦc#o>֒qR9Rcg[W(>-WhW&.{mH?ژ7,q/8LdFe}a&uYmUUǭ۳_-_ ջo q[Gk.Z}φ߭jzJקim_}/?JW o[ ۏJuu_c1ލhtZjus4{@"^gc̳QQWF[6O݃g[w}curc}L>w%4,AYn>uu0[o};qQt-+^cUٴ j_<@/݇ܬe[[M32,o=6N} dao{}?qsyؤ"TWXƐ_!U榢uVIcf~I'%_$)7#|'RK$];^_jYEH,2ji4H=~y(TRӗFZu_WC # $R⠲N(-܇:XJrVu^/^Җ4TGAEucW}Ü9s'߶,L~<(#V^-d…zD@IDATg 7~{~?<_-n;ϧcvimJKm&kQ]?CZ|]ˆސ[|yQ[חϿ,flTNiE!nnWEYcWg=YuTɦrHSDZtá`:,sϭsG#2Fc{Z/Ms:=Z.Z^Ia8~goY#֭xuYR@ijieǰe0^I F['xb-/ VZ= z1VvՓ8IN8*kTl=>ڏYK43)-l]:4̏ݣ'٢BaҌF[Og#e듲 ~E%}/!-]U 4i{Je\ʢk=q'9quGOzkW>tQ#Zku1gj'Pݫ^TҰ5h[%OmM*y-Yĵ2ho!{ї,Ok7,XڵԲɶ^E$jm&WPj>Z>rI0k@imjKaMJ<1ڇPgOPV'Žm?j#:XC9@#PsQS ?4k zκwR!h}hRY34$=MNg--3oHdr= Vu`;~jZDpdи@SP0Y/-9 c$1EwU9q1n(WԲLgNFIrEHcS:`"%vۨey9N{pߢ:jnse$UDQaF'C)U'Gy 4c_f Ty%Tm_yË4Ϋ^~L2nÑÌ.lta~);~O97%`}d0,?k?Mp1p\Γ(WXi$־Cmg2D_zӧ7T07@ZB*͸)=@ @`:B!~[ڟW;6m)@:G@j0 @ )ά4 @ @(OZyV @ @@JZ  @ @@V!!@ @ @@ @ gEH@ @ (@ @ @<kY @ @)k) , @ @(OZyV @ @@JZ  @ @@V!!@ @ @@ @ gEH@ @ (@ @ @<B5:5 @ @@_ȓ=womn-W@ @ k]]!Y j$B @ @)Q1ݓ¤FL(~B @ @`|Vi쎻'HФꆁ @ @&rdgƄF+ @ @*.'wuW'nݺp}]v%!~G}t3%@ώ'@=/ϊxi۶m O?tزeK';$;cPs.7&0^֭[SO=|䪧:mڴN;%)SLٗHJdwӦMΝic$  0 un*J ֔u`U',&"kغm͉pQ: PSU Pϫ#D"0^ڇ>~zSNMKM&ң{IPQoߞeÆ 4פe5ֲD I`41g:H@KS3o4H`Y'},~ŧFW%FD`,*vm7? %F<հˍUyaWϣ/U%V~<_UbWϣ/U%V~<_UbWpop뭷&tC G}t8cCy~yTʻOh%Lc2e 旞L9;sjJ-T(?W?!S?/*[vy0sf; F瘭5)]a ִiZOb'hhJfg$ڻ¯=n ~F+fg$ڻ¯=n ~F+fW#$y䑠Ns=ٳ\k!_=WX}x ~UՇ?_Vym=hݟ]㯬1Āˤ+6@ @ @,keI @ @5+ @ @@V @ @  Xs0B @ @,keI @ @5+ @ @޺8h__ fok7GD{WbHw_{,D{WbHw_{,D{Wոi^m[۷OdHkY,kłh:ZY򙑽UnaUWݛ7%¤]_0z , (`wb *¯IU~L ưkdRťߓO5!h%7͑X?%W?U!PUIÇs ު?E*X ZDw@ @ 4!=}zo"35j VG_&3u6\ͥ:3~Fu;31iTï:3~Fu;31iTï:3~5;Ž;#6Jɯh?_W?O~ՙ'VV@|[U)U6Fa^4R/fyɇT~l 0+fS~e(_12>+C8 ٔ_JaWc&^DvɯhU~e(_12>+C8hg[w:ci6{/(2@ @ BDy' @ @@68I  @ @`@6Q4 @ @ 0 )N @ @(M'}B @  )kC @ @& kIs @ @CJڐ$1@ @ BDy' @ @@68I  @ @`@6Q4 @ @ 0 )N @ @(Zֺow2y{G 2evV_&oh\Lt-ܗ]Z}r2y Q/wP.s_&owA:jee.HGLB}՗;Z(/ 2y{G 2evV_&oh\Lt-ܗ]Z}r2y Q/wP.s_&owA:jee.HGLB[FE) @ @Fr U>ʯ߻Τyqr8)I<ٷo(teIRhiehjiZAr=__r+F# KCh@2/ӿhn3yrܦ+]nk#~iE؝;YC @ ] @ @$` @ @`@6v% @ @ kO @ @c(9 @ @@ X | @ @gG!@ @:HZ5 @ @%`m>;J@ @ A:!@ @.kcQr@ @ ޺8'BWWJçn:kłh Y,kłh Y,qӼd۶o.7͑^X3]7?#u\3#{]ȯ7o.J&IQ%`Y==Q< `?_Uh5_#*.B1,Tq_ZaȤK' kB4$Jn+#1jK~B;ZUnaU" @ @hB{bDBgj\ISMfmK)_uf>j4v)wGl:r_ ~6Uï:3~Fu;31F+?'O(*)Smn0h7X_\.+C8 ٔ_JaW̦P*b6e|WRq)2FsM4r_<~uP*b6e|WRqsuϋtl^P! d  @ @O@ @ !%`mHq @ @D!`mw`m$( @ 0ja={g&fZk2 0R_}v񲏄A6 @5;ɾu'c @`lߵ}zڿ] X @ &MJ4 ٰaCGϨ)( zzzo {oy<9`@  @ 06Lnɟ'HNMZa @`P:T}d(9oL @!0u0sOvۣ' 頣6 0 Hvo30dݐ$$8@ @㙀6cƌd]w5Nx !F' OvTcݣ6cP*@ @` N|f8¯qưzdnÔ#sMaMkC0Ng f sg>oY._"ydcr3z /ׄ+^3ÂS4\,^Bo3-/f+šj0x>}3-0w0ҠݲimXea kBSswTXaakyyvb[^9i0{vHJ&}߻>㴶+-;XGxCzա~r5ŇNBR\;|_6mgPx3o 4i'm۶YK4&M- ̚?QWmfեaIsº/G-t<>~BX}auHvii^zUXjuo~~0}dVV;8շțd^ U޿[{2)!n ]BiQ+qx{V(=~U~;*\XU&VoT/q_&wk0{Mvソ >X_',B3mQ?? œjQ@2c_7\vk:yk`s{W_sGZ-\sñ̰B7+}[/, k> q1Ɯ5j]q@|fA !ws<-\p'\bݼ6 ֆ=޴4,M=jh{ׇU_/|,pjdgaIذ" זi(o `ڻ=4|o{a>n`~׆vP͎{9=e(o LU0 @&;tg<#y估iy樹>ܷvmdቸ7jD9iCL&O4񠕺g(lq#ÀT@mlf7K gui ߻8}]>ZV(,Nev7*ˢ /{>55;nͼ79'e~ht]Sxr岛ׅ/"X:nUz{{x#>hՉPMB6{FxG#b.w)_4j$2ݓ2N+]2)_d7֩5)XH? ?oBBRP//>__kG/gxы^e!.YDm wFͦE!,~GIKNhF.u}jup,ie p^ngdžS޺(/ INE\2!O eኝ焰sɍ-ӊqw}RH QK\4uV[-3+<ԟmp k^6$0wNa&%0#}Qcy2'.|\pW/|`A͵WVZ3^r{ U]raz7W.Zp. s)\{f X-Mkk3 _1'2{}^xՕM 3wB}uM\aK:37S^5z"G3O{BgεxYXɱ30W Oݴ>,a͵SGu7.eY\>؅qu] ?@CԴ[r޸8,贙=)Y :-[{6Uяn֮7ISMF|W2s g$TiU,Qu?G ^pyqtU4|_+BלO+_"~_+BלO+_"~_wf~Vy*.5uC ֯_'rkC |cx,.ݰg>+nqiNavkSC&-I%':}NQ<ցή#yᰅdJ{YoKsorgTwև6;LZJdsZt0贈anbꡧeoՅ׺,,:m]XG\7߰&{²N-g=^tYh\a})u.^uS-[xrWy|M['|;rN"T+8$'{B^BHrmY$׌Nk?f,i֌_3:ךQkFZ3j~_8Cٌ3MiCHH&|0mذ!Y$ Mk&\++X6dt oI ii܀.}EXн"wŠK^e>.\va>mο.x/+Qc{n eǦO1e(ܹ{Ò58`wja^O5SSz +`SsGͣ:Ayw. WKv[M\ZmN.ׅ' koZ-rOo50P_]pg/O kW/ ]\ kEtMyaa"Vg4s|Uaפ;™@s\z횛xkwO,}.xQ7].eiQ{Bv%ި17&f' K4',;pi/pމ!,}a~n5,Kd W^pݚi~fixꟇo&XzgVfkOU-2AĤVߴ6.k?%.vҚay7Qbr"$T RO ;DCm̙ưAZ*틍 @%I&p͞=;j=,m@<>\ӒG}4 fAiH`c{ornڤsr~m/s~5 hb!8:3zdeiAyyuk#RlYjaOrWI6Єl͌>!UHVeg1 Y.$Ye#NdU k{Z_f.     Bd;xmo ~I QKY4!Z+{}aU׈o_E_e5t')ܸz.f.:fy"= 髚}Cl09Qm-.f⧞Qmk᭖KE"h׽6y>,x|~PE(};W*]K7IxM_]š}ԫsUж߿s nGD      8"3Q,76+iquuwrZpjC4ǻiK,|?z=Qi1Ag,ͮt'$݌UT;{i;NrmMn2EyPmJ^}0VWс8]{K oZ'5mi 9S!ҟ6#\v:3"|bզ4Ũkk%mFƮ~aѿ l`       %铠4pi|=E51/uIݕv֖dmtS.ѱIcz8cj{a*R/L #Ӝå狱 GdfD#%c]T2V_ Ӻ!Ϛ_zOSt,M|# !Y ٫*!ai `9BjsK秅uQhgGh@O62Zrf RouM7d=I^ɸ?uSd2c\lA2%ɐŧK4)gCǣ=MQr%@%n{//cfi\D     -J E=OxNݔӳzfZ'ޠq$eܻ7B8 ^[`ͧ(}5$Ph?J ;({6I=>u5 fS Prҙb᥾0S.I[Z$q&`ԍP'c%.F"g>8%p" O1=3FUp`\ȡȠ^WT!Scd |@btQ%5n9>fZ      -I"fqfLY 1J 3ǻ>r9#+H}$AܰU-{˟/34+e w RE_k|fƨ,_6rdе3F*74-m?(V/7ӷb0J#k[r9kb3FZ\3R/~S 6qbWz:X_iku @XFp      {@p{OT^oMR,d?Lk47V̱tL34?. Yu֯/Eh[NMfI{Ӏ~Uv mO~NZBt(h&gX%ydIlбa1MS.g}lvsǩ''1^,(Z Y?:|Jv#v@`[^N񹭜8qr?72j Ȩ'7+s#6~jܬύ8qrj~mmwXDz 3ؗ>J1,X 9m?;zKCAb*X%?s̿-52%bE<Цx}JY6,g=f+{Rpc,a$ Z [,9GdV䭎[A}!څ[!mߺ!ߌ#~~вۂCn ~v&~F--ٙ??{߾}vM?‰/`Ds˯/N耞N`ˆwFƵ+DR9ڷk1 ֐sDJF߯vCs2i㍢EoB>[P;Y1Sgd ~NTO%9QQ?uVNDE} Y9YVגšrԶFJS""hB7j߿ү5?F4qy^sOS49|ey#Ȝ8~~uTl}pi&:^}Uge~^t_ꌼ,ϋNkWyѩ~ 3?/:կ_uF^EVo_T =F@ }m۽`67X M`"fhsŸ* >J6F Pr?w6*WO Q~*mϝSn~lT? ! V)R-v:)@@@@@@@@1k8 uSc\B @@@@@@`7@ǭ=**zQjD-.4}|Cn?  %3+U^IDATBE}IENDB`kcp-go-5.6.1/go.mod000066400000000000000000000014021374022726700140200ustar00rootroot00000000000000module github.com/xtaci/kcp-go/v5 require ( github.com/klauspost/cpuid v1.3.1 // indirect github.com/klauspost/reedsolomon v1.9.9 github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 // indirect github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.6.1 github.com/templexxx/cpu v0.0.7 // indirect github.com/templexxx/xorsimd v0.4.1 github.com/tjfoc/gmsm v1.3.2 github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 // indirect golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) go 1.13 kcp-go-5.6.1/go.sum000066400000000000000000000151261374022726700140550ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54= github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo= github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 h1:ULR/QWMgcgRiZLUjSSJMU+fW+RDMstRdmnDWj9Q+AsA= github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/templexxx/cpu v0.0.1 h1:hY4WdLOgKdc8y13EYklu9OUTXik80BkxHoWvTO6MQQY= github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/templexxx/cpu v0.0.7 h1:pUEZn8JBy/w5yzdYWgx+0m0xL9uk6j4K91C5kOViAzo= github.com/templexxx/cpu v0.0.7/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/templexxx/xorsimd v0.4.1 h1:iUZcywbOYDRAZUasAs2eSCUW8eobuZDy0I9FJiORkVg= github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo= github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 h1:yi1hN8dcqI9l8klZfy4B8mJvFmmAxJEePIQQFNSd7Cs= golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU= golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123 h1:4JSJPND/+4555t1HfXYF4UEqDqiSKCgeV0+hbA8hMs4= golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= kcp-go-5.6.1/kcp-go.png000066400000000000000000000217011374022726700146040ustar00rootroot00000000000000PNG  IHDRbߜ iCCPICC ProfileHWXS[R -)wW]6B AŎ.*vQZY+ve"*+b *oR@׾wo9sΙ=w2 +77 U / e&$&1I݀Y'[7ıu2+dDB!> @hz9b<qq[Jlb Lei(y3 i0 C\ ';Ł!Ė9+!6M.NbdƱ4y,ּs9dgЇ. ׭&3'TৄG@eGb/E2`?b-Xc $ p 'J-gL熌\a@M*/0bXix)O|/.b;ѡ2Dž~c6Q!RQRL=[8ffI悵yK}0!l qX7 Vo̷87+RffEI;$,ʇ&]IkJl)7a&r@4 _ґ@J󈗌3?!ḟd ˸VG&xq6{x|zfc~LűYDb01h6΃ Yg& =f'[<3B' pā(2ټ"̙`*e٥c61d?3pM`;L|p/#~P4Z8 2)oo(~߭?Zb+#%,v;5&vkڰb<^ O%06[[&,s?y^Zz>\fmmɴu@K ɞ0~*ӾX} ,u`Rx;  )8w b@"W<dCsRl`'jAp4,p 1D"hBte"18@\FO>E"?')ɹEqɭ+"w]OnL1xPb(zC[yyy}yWi<%[_HUS3"j5 -F3yӒh5Z9cBGaBBB+E9E#EYeG+()+))U(W4LWUPV^_ J Ges*tn@{}DU RՃj*jjqjs*Nu301#X8̸4A{U'tMx>Q[^ޠ~KS#@#ScF#M\\s4&NtȞX2ZV|=ZmZC:Aڹ۴i0tu2t6ץzt7af123DzFMcP \ R 6 N5\`XgxH(h%&+_ԙ<4zV4#em70G+̯[N<KWKe+UUU5:̺Ⱥ$IIO4髍M^*Sll[lؙ۱*n7ۿvp:pHw±񋓳ީ9ٹKjˮW_Ů'\?9v=}&N`ydz&{byUy=6x~cs畯{?7~g1 ؀ǁiuAAC aԆ NqpPjhthy00AXTtꔩ> 7 7E"M""F9bڳ(ۨQѳGƬyk+mSW>?~C|w¤ 5yI}ICo7qF3MfΝye欬Y'g+f>LHOޟb T [/9ޜM~wyGiiӽx~r3#23G*L9Źyny}BD8S؜ 9m"SOςs>ܷYs/^c}/s_ g+WGm0ao5Vsx:9x8{x}5]>^ȜϤ[}ihh.K0TT@Kg( һD}QDɥ%3، ^|x0N o0o E0::}t^Hgw>~QOl*A pHYs%%IR$SIDATxxVEr+ T z H*rR9sx8`\@Y\@x`p 9偵9swW{Ь%Ҳ yPܜm um U!4}y<85Rr a'!t0A0d$X9*WƨGD 2"ƹ68zW^h(ս7m!;d-lmέ8{]]wp7@@t sqMa-k"(vжi]s33͛YPN_N}HÌݲ+w>|(DKA \ڍ)Wi̙ %_&|~"n|)>HVEέ.}˦{Ƨ!/ڀ3g;?*݂M #t'[ };@V,Ty!çߟٲm.IYK.V`Ǚ >c%bup<*.9t/7#D\[D/`ȋ0pvY#J)pu4 غBБy"pVRTkɰ|ӟp'6]UyB_6%'9G(f 8;IUC.Y)҂Iޘ |')OKvGKO՘tt%?_uVйE=r\Ր~Ug 7qխ8+" `r; `īLTk{q*,]g /Z?jyibbt$dy')̦IaYϫ~0Y6?F >,:qzPt?kg' [pezԲaKgמ#lw5I@/ Tp4~Y9VGMM% =$ cT a=BNX;զBOU0zv +k#k {BwOv]3DY !l u!}qvvBaq/4[F7{C [+I,ASx 6{`L >}%'nxZc'nE~N,](A"z05yP/IMXPhр$뫞o/> aWq6pt > 1'4ZNȍnN}2fP|W}:_">}s| pfo pڱ)Vwƴ&kh|}= gadh1xgY(`SVL:$7{%CH?G˪G?ޛd^cl-ͧ@xjĮÊ#BbPcGPc:G ^؁v h+& ; a!]5t5~h,M<XlPahc,g|q' 1.h)1(S 98klYQ) Vq?qYw(q]5oph=opiu.1T߭s? ܿ1dia"t9 2NJsj ͂@aA, wK_.}v'Kpmڜ&_r'x'TФӜНy1<Xp}t'ѡw7B L&cx`lY 3iXꬺ5PY߼19x 89³ ,]72Rre qJќ5̈AG1*,uc;!jeҰu(xՋ6‘ϸX;=%&"{|= b { return a } return b } func _ibound_(lower, middle, upper uint32) uint32 { return _imin_(_imax_(lower, middle), upper) } func _itimediff(later, earlier uint32) int32 { return (int32)(later - earlier) } // segment defines a KCP segment type segment struct { conv uint32 cmd uint8 frg uint8 wnd uint16 ts uint32 sn uint32 una uint32 rto uint32 xmit uint32 resendts uint32 fastack uint32 acked uint32 // mark if the seg has acked data []byte } // encode a segment into buffer func (seg *segment) encode(ptr []byte) []byte { ptr = ikcp_encode32u(ptr, seg.conv) ptr = ikcp_encode8u(ptr, seg.cmd) ptr = ikcp_encode8u(ptr, seg.frg) ptr = ikcp_encode16u(ptr, seg.wnd) ptr = ikcp_encode32u(ptr, seg.ts) ptr = ikcp_encode32u(ptr, seg.sn) ptr = ikcp_encode32u(ptr, seg.una) ptr = ikcp_encode32u(ptr, uint32(len(seg.data))) atomic.AddUint64(&DefaultSnmp.OutSegs, 1) return ptr } // KCP defines a single KCP connection type KCP struct { conv, mtu, mss, state uint32 snd_una, snd_nxt, rcv_nxt uint32 ssthresh uint32 rx_rttvar, rx_srtt int32 rx_rto, rx_minrto uint32 snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe uint32 interval, ts_flush uint32 nodelay, updated uint32 ts_probe, probe_wait uint32 dead_link, incr uint32 fastresend int32 nocwnd, stream int32 snd_queue []segment rcv_queue []segment snd_buf []segment rcv_buf []segment acklist []ackItem buffer []byte reserved int output output_callback } type ackItem struct { sn uint32 ts uint32 } // NewKCP create a new kcp state machine // // 'conv' must be equal in the connection peers, or else data will be silently rejected. // // 'output' function will be called whenever these is data to be sent on wire. func NewKCP(conv uint32, output output_callback) *KCP { kcp := new(KCP) kcp.conv = conv kcp.snd_wnd = IKCP_WND_SND kcp.rcv_wnd = IKCP_WND_RCV kcp.rmt_wnd = IKCP_WND_RCV kcp.mtu = IKCP_MTU_DEF kcp.mss = kcp.mtu - IKCP_OVERHEAD kcp.buffer = make([]byte, kcp.mtu) kcp.rx_rto = IKCP_RTO_DEF kcp.rx_minrto = IKCP_RTO_MIN kcp.interval = IKCP_INTERVAL kcp.ts_flush = IKCP_INTERVAL kcp.ssthresh = IKCP_THRESH_INIT kcp.dead_link = IKCP_DEADLINK kcp.output = output return kcp } // newSegment creates a KCP segment func (kcp *KCP) newSegment(size int) (seg segment) { seg.data = xmitBuf.Get().([]byte)[:size] return } // delSegment recycles a KCP segment func (kcp *KCP) delSegment(seg *segment) { if seg.data != nil { xmitBuf.Put(seg.data) seg.data = nil } } // ReserveBytes keeps n bytes untouched from the beginning of the buffer, // the output_callback function should be aware of this. // // Return false if n >= mss func (kcp *KCP) ReserveBytes(n int) bool { if n >= int(kcp.mtu-IKCP_OVERHEAD) || n < 0 { return false } kcp.reserved = n kcp.mss = kcp.mtu - IKCP_OVERHEAD - uint32(n) return true } // PeekSize checks the size of next message in the recv queue func (kcp *KCP) PeekSize() (length int) { if len(kcp.rcv_queue) == 0 { return -1 } seg := &kcp.rcv_queue[0] if seg.frg == 0 { return len(seg.data) } if len(kcp.rcv_queue) < int(seg.frg+1) { return -1 } for k := range kcp.rcv_queue { seg := &kcp.rcv_queue[k] length += len(seg.data) if seg.frg == 0 { break } } return } // Receive data from kcp state machine // // Return number of bytes read. // // Return -1 when there is no readable data. // // Return -2 if len(buffer) is smaller than kcp.PeekSize(). func (kcp *KCP) Recv(buffer []byte) (n int) { peeksize := kcp.PeekSize() if peeksize < 0 { return -1 } if peeksize > len(buffer) { return -2 } var fast_recover bool if len(kcp.rcv_queue) >= int(kcp.rcv_wnd) { fast_recover = true } // merge fragment count := 0 for k := range kcp.rcv_queue { seg := &kcp.rcv_queue[k] copy(buffer, seg.data) buffer = buffer[len(seg.data):] n += len(seg.data) count++ kcp.delSegment(seg) if seg.frg == 0 { break } } if count > 0 { kcp.rcv_queue = kcp.remove_front(kcp.rcv_queue, count) } // move available data from rcv_buf -> rcv_queue count = 0 for k := range kcp.rcv_buf { seg := &kcp.rcv_buf[k] if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue)+count < int(kcp.rcv_wnd) { kcp.rcv_nxt++ count++ } else { break } } if count > 0 { kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...) kcp.rcv_buf = kcp.remove_front(kcp.rcv_buf, count) } // fast recover if len(kcp.rcv_queue) < int(kcp.rcv_wnd) && fast_recover { // ready to send back IKCP_CMD_WINS in ikcp_flush // tell remote my window size kcp.probe |= IKCP_ASK_TELL } return } // Send is user/upper level send, returns below zero for error func (kcp *KCP) Send(buffer []byte) int { var count int if len(buffer) == 0 { return -1 } // append to previous segment in streaming mode (if possible) if kcp.stream != 0 { n := len(kcp.snd_queue) if n > 0 { seg := &kcp.snd_queue[n-1] if len(seg.data) < int(kcp.mss) { capacity := int(kcp.mss) - len(seg.data) extend := capacity if len(buffer) < capacity { extend = len(buffer) } // grow slice, the underlying cap is guaranteed to // be larger than kcp.mss oldlen := len(seg.data) seg.data = seg.data[:oldlen+extend] copy(seg.data[oldlen:], buffer) buffer = buffer[extend:] } } if len(buffer) == 0 { return 0 } } if len(buffer) <= int(kcp.mss) { count = 1 } else { count = (len(buffer) + int(kcp.mss) - 1) / int(kcp.mss) } if count > 255 { return -2 } if count == 0 { count = 1 } for i := 0; i < count; i++ { var size int if len(buffer) > int(kcp.mss) { size = int(kcp.mss) } else { size = len(buffer) } seg := kcp.newSegment(size) copy(seg.data, buffer[:size]) if kcp.stream == 0 { // message mode seg.frg = uint8(count - i - 1) } else { // stream mode seg.frg = 0 } kcp.snd_queue = append(kcp.snd_queue, seg) buffer = buffer[size:] } return 0 } func (kcp *KCP) update_ack(rtt int32) { // https://tools.ietf.org/html/rfc6298 var rto uint32 if kcp.rx_srtt == 0 { kcp.rx_srtt = rtt kcp.rx_rttvar = rtt >> 1 } else { delta := rtt - kcp.rx_srtt kcp.rx_srtt += delta >> 3 if delta < 0 { delta = -delta } if rtt < kcp.rx_srtt-kcp.rx_rttvar { // if the new RTT sample is below the bottom of the range of // what an RTT measurement is expected to be. // give an 8x reduced weight versus its normal weighting kcp.rx_rttvar += (delta - kcp.rx_rttvar) >> 5 } else { kcp.rx_rttvar += (delta - kcp.rx_rttvar) >> 2 } } rto = uint32(kcp.rx_srtt) + _imax_(kcp.interval, uint32(kcp.rx_rttvar)<<2) kcp.rx_rto = _ibound_(kcp.rx_minrto, rto, IKCP_RTO_MAX) } func (kcp *KCP) shrink_buf() { if len(kcp.snd_buf) > 0 { seg := &kcp.snd_buf[0] kcp.snd_una = seg.sn } else { kcp.snd_una = kcp.snd_nxt } } func (kcp *KCP) parse_ack(sn uint32) { if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 { return } for k := range kcp.snd_buf { seg := &kcp.snd_buf[k] if sn == seg.sn { // mark and free space, but leave the segment here, // and wait until `una` to delete this, then we don't // have to shift the segments behind forward, // which is an expensive operation for large window seg.acked = 1 kcp.delSegment(seg) break } if _itimediff(sn, seg.sn) < 0 { break } } } func (kcp *KCP) parse_fastack(sn, ts uint32) { if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 { return } for k := range kcp.snd_buf { seg := &kcp.snd_buf[k] if _itimediff(sn, seg.sn) < 0 { break } else if sn != seg.sn && _itimediff(seg.ts, ts) <= 0 { seg.fastack++ } } } func (kcp *KCP) parse_una(una uint32) int { count := 0 for k := range kcp.snd_buf { seg := &kcp.snd_buf[k] if _itimediff(una, seg.sn) > 0 { kcp.delSegment(seg) count++ } else { break } } if count > 0 { kcp.snd_buf = kcp.remove_front(kcp.snd_buf, count) } return count } // ack append func (kcp *KCP) ack_push(sn, ts uint32) { kcp.acklist = append(kcp.acklist, ackItem{sn, ts}) } // returns true if data has repeated func (kcp *KCP) parse_data(newseg segment) bool { sn := newseg.sn if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) >= 0 || _itimediff(sn, kcp.rcv_nxt) < 0 { return true } n := len(kcp.rcv_buf) - 1 insert_idx := 0 repeat := false for i := n; i >= 0; i-- { seg := &kcp.rcv_buf[i] if seg.sn == sn { repeat = true break } if _itimediff(sn, seg.sn) > 0 { insert_idx = i + 1 break } } if !repeat { // replicate the content if it's new dataCopy := xmitBuf.Get().([]byte)[:len(newseg.data)] copy(dataCopy, newseg.data) newseg.data = dataCopy if insert_idx == n+1 { kcp.rcv_buf = append(kcp.rcv_buf, newseg) } else { kcp.rcv_buf = append(kcp.rcv_buf, segment{}) copy(kcp.rcv_buf[insert_idx+1:], kcp.rcv_buf[insert_idx:]) kcp.rcv_buf[insert_idx] = newseg } } // move available data from rcv_buf -> rcv_queue count := 0 for k := range kcp.rcv_buf { seg := &kcp.rcv_buf[k] if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue)+count < int(kcp.rcv_wnd) { kcp.rcv_nxt++ count++ } else { break } } if count > 0 { kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...) kcp.rcv_buf = kcp.remove_front(kcp.rcv_buf, count) } return repeat } // Input a packet into kcp state machine. // // 'regular' indicates it's a real data packet from remote, and it means it's not generated from ReedSolomon // codecs. // // 'ackNoDelay' will trigger immediate ACK, but surely it will not be efficient in bandwidth func (kcp *KCP) Input(data []byte, regular, ackNoDelay bool) int { snd_una := kcp.snd_una if len(data) < IKCP_OVERHEAD { return -1 } var latest uint32 // the latest ack packet var flag int var inSegs uint64 var windowSlides bool for { var ts, sn, length, una, conv uint32 var wnd uint16 var cmd, frg uint8 if len(data) < 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, &length) if len(data) < int(length) { return -2 } if cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK && cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS { return -3 } // only trust window updates from regular packets. i.e: latest update if regular { kcp.rmt_wnd = uint32(wnd) } if kcp.parse_una(una) > 0 { windowSlides = true } kcp.shrink_buf() if cmd == IKCP_CMD_ACK { kcp.parse_ack(sn) kcp.parse_fastack(sn, ts) flag |= 1 latest = ts } else if cmd == IKCP_CMD_PUSH { repeat := true if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) < 0 { kcp.ack_push(sn, ts) if _itimediff(sn, kcp.rcv_nxt) >= 0 { var seg segment seg.conv = conv seg.cmd = cmd seg.frg = frg seg.wnd = wnd seg.ts = ts seg.sn = sn seg.una = una seg.data = data[:length] // delayed data copying repeat = kcp.parse_data(seg) } } if regular && repeat { atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1) } } 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 } else if cmd == IKCP_CMD_WINS { // do nothing } else { return -3 } inSegs++ data = data[length:] } atomic.AddUint64(&DefaultSnmp.InSegs, inSegs) // update rtt with the latest ts // ignore the FEC packet if flag != 0 && regular { current := currentMs() if _itimediff(current, latest) >= 0 { kcp.update_ack(_itimediff(current, latest)) } } // cwnd update when packet arrived if kcp.nocwnd == 0 { if _itimediff(kcp.snd_una, snd_una) > 0 { if kcp.cwnd < kcp.rmt_wnd { 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 mss > 0 { kcp.cwnd = (kcp.incr + mss - 1) / mss } else { kcp.cwnd = kcp.incr + mss - 1 } } } if kcp.cwnd > kcp.rmt_wnd { kcp.cwnd = kcp.rmt_wnd kcp.incr = kcp.rmt_wnd * mss } } } } if windowSlides { // if window has slided, flush kcp.flush(false) } else if ackNoDelay && len(kcp.acklist) > 0 { // ack immediately kcp.flush(true) } return 0 } func (kcp *KCP) wnd_unused() uint16 { if len(kcp.rcv_queue) < int(kcp.rcv_wnd) { return uint16(int(kcp.rcv_wnd) - len(kcp.rcv_queue)) } return 0 } // flush pending data func (kcp *KCP) flush(ackOnly bool) uint32 { var seg segment seg.conv = kcp.conv seg.cmd = IKCP_CMD_ACK seg.wnd = kcp.wnd_unused() seg.una = kcp.rcv_nxt buffer := kcp.buffer ptr := buffer[kcp.reserved:] // keep n bytes untouched // makeSpace makes room for writing makeSpace := func(space int) { size := len(buffer) - len(ptr) if size+space > int(kcp.mtu) { kcp.output(buffer, size) ptr = buffer[kcp.reserved:] } } // flush bytes in buffer if there is any flushBuffer := func() { size := len(buffer) - len(ptr) if size > kcp.reserved { kcp.output(buffer, size) } } // flush acknowledges for i, ack := range kcp.acklist { makeSpace(IKCP_OVERHEAD) // filter jitters caused by bufferbloat if _itimediff(ack.sn, kcp.rcv_nxt) >= 0 || len(kcp.acklist)-1 == i { seg.sn, seg.ts = ack.sn, ack.ts ptr = seg.encode(ptr) } } kcp.acklist = kcp.acklist[0:0] if ackOnly { // flash remain ack segments flushBuffer() return kcp.interval } // probe window size (if remote window size equals zero) if kcp.rmt_wnd == 0 { current := currentMs() if kcp.probe_wait == 0 { kcp.probe_wait = IKCP_PROBE_INIT kcp.ts_probe = current + kcp.probe_wait } else { if _itimediff(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 = 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) != 0 { seg.cmd = IKCP_CMD_WASK makeSpace(IKCP_OVERHEAD) ptr = seg.encode(ptr) } // flush window probing commands if (kcp.probe & IKCP_ASK_TELL) != 0 { seg.cmd = IKCP_CMD_WINS makeSpace(IKCP_OVERHEAD) ptr = seg.encode(ptr) } kcp.probe = 0 // calculate window size cwnd := _imin_(kcp.snd_wnd, kcp.rmt_wnd) if kcp.nocwnd == 0 { cwnd = _imin_(kcp.cwnd, cwnd) } // sliding window, controlled by snd_nxt && sna_una+cwnd newSegsCount := 0 for k := range kcp.snd_queue { if _itimediff(kcp.snd_nxt, kcp.snd_una+cwnd) >= 0 { break } newseg := kcp.snd_queue[k] newseg.conv = kcp.conv newseg.cmd = IKCP_CMD_PUSH newseg.sn = kcp.snd_nxt kcp.snd_buf = append(kcp.snd_buf, newseg) kcp.snd_nxt++ newSegsCount++ } if newSegsCount > 0 { kcp.snd_queue = kcp.remove_front(kcp.snd_queue, newSegsCount) } // calculate resent resent := uint32(kcp.fastresend) if kcp.fastresend <= 0 { resent = 0xffffffff } // check for retransmissions current := currentMs() var change, lostSegs, fastRetransSegs, earlyRetransSegs uint64 minrto := int32(kcp.interval) ref := kcp.snd_buf[:len(kcp.snd_buf)] // for bounds check elimination for k := range ref { segment := &ref[k] needsend := false if segment.acked == 1 { continue } if segment.xmit == 0 { // initial transmit needsend = true segment.rto = kcp.rx_rto segment.resendts = current + segment.rto } else if segment.fastack >= resent { // fast retransmit needsend = true segment.fastack = 0 segment.rto = kcp.rx_rto segment.resendts = current + segment.rto change++ fastRetransSegs++ } else if segment.fastack > 0 && newSegsCount == 0 { // early retransmit needsend = true segment.fastack = 0 segment.rto = kcp.rx_rto segment.resendts = current + segment.rto change++ earlyRetransSegs++ } else if _itimediff(current, segment.resendts) >= 0 { // RTO needsend = true if kcp.nodelay == 0 { segment.rto += kcp.rx_rto } else { segment.rto += kcp.rx_rto / 2 } segment.fastack = 0 segment.resendts = current + segment.rto lostSegs++ } if needsend { current = currentMs() segment.xmit++ segment.ts = current segment.wnd = seg.wnd segment.una = seg.una need := IKCP_OVERHEAD + len(segment.data) makeSpace(need) ptr = segment.encode(ptr) copy(ptr, segment.data) ptr = ptr[len(segment.data):] if segment.xmit >= kcp.dead_link { kcp.state = 0xFFFFFFFF } } // get the nearest rto if rto := _itimediff(segment.resendts, current); rto > 0 && rto < minrto { minrto = rto } } // flash remain segments flushBuffer() // counter updates sum := lostSegs if lostSegs > 0 { atomic.AddUint64(&DefaultSnmp.LostSegs, lostSegs) } if fastRetransSegs > 0 { atomic.AddUint64(&DefaultSnmp.FastRetransSegs, fastRetransSegs) sum += fastRetransSegs } if earlyRetransSegs > 0 { atomic.AddUint64(&DefaultSnmp.EarlyRetransSegs, earlyRetransSegs) sum += earlyRetransSegs } if sum > 0 { atomic.AddUint64(&DefaultSnmp.RetransSegs, sum) } // cwnd update if kcp.nocwnd == 0 { // update ssthresh // rate halving, https://tools.ietf.org/html/rfc6937 if change > 0 { 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 } // congestion control, https://tools.ietf.org/html/rfc5681 if lostSegs > 0 { 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 } } return uint32(minrto) } // (deprecated) // // Update updates 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. func (kcp *KCP) Update() { var slap int32 current := currentMs() if kcp.updated == 0 { kcp.updated = 1 kcp.ts_flush = current } slap = _itimediff(current, kcp.ts_flush) if slap >= 10000 || slap < -10000 { kcp.ts_flush = current slap = 0 } if slap >= 0 { kcp.ts_flush += kcp.interval if _itimediff(current, kcp.ts_flush) >= 0 { kcp.ts_flush = current + kcp.interval } kcp.flush(false) } } // (deprecated) // // Check determines 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) func (kcp *KCP) Check() uint32 { current := currentMs() ts_flush := kcp.ts_flush tm_flush := int32(0x7fffffff) tm_packet := int32(0x7fffffff) minimal := uint32(0) 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 k := range kcp.snd_buf { seg := &kcp.snd_buf[k] diff := _itimediff(seg.resendts, current) if diff <= 0 { return current } if diff < tm_packet { tm_packet = diff } } minimal = uint32(tm_packet) if tm_packet >= tm_flush { minimal = uint32(tm_flush) } if minimal >= kcp.interval { minimal = kcp.interval } return current + minimal } // SetMtu changes MTU size, default is 1400 func (kcp *KCP) SetMtu(mtu int) int { if mtu < 50 || mtu < IKCP_OVERHEAD { return -1 } if kcp.reserved >= int(kcp.mtu-IKCP_OVERHEAD) || kcp.reserved < 0 { return -1 } buffer := make([]byte, mtu) if buffer == nil { return -2 } kcp.mtu = uint32(mtu) kcp.mss = kcp.mtu - IKCP_OVERHEAD - uint32(kcp.reserved) kcp.buffer = buffer return 0 } // NoDelay options // 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 func (kcp *KCP) NoDelay(nodelay, interval, resend, nc int) int { if nodelay >= 0 { kcp.nodelay = uint32(nodelay) if nodelay != 0 { 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 = uint32(interval) } if resend >= 0 { kcp.fastresend = int32(resend) } if nc >= 0 { kcp.nocwnd = int32(nc) } return 0 } // WndSize sets maximum window size: sndwnd=32, rcvwnd=32 by default func (kcp *KCP) WndSize(sndwnd, rcvwnd int) int { if sndwnd > 0 { kcp.snd_wnd = uint32(sndwnd) } if rcvwnd > 0 { kcp.rcv_wnd = uint32(rcvwnd) } return 0 } // WaitSnd gets how many packet is waiting to be sent func (kcp *KCP) WaitSnd() int { return len(kcp.snd_buf) + len(kcp.snd_queue) } // remove front n elements from queue // if the number of elements to remove is more than half of the size. // just shift the rear elements to front, otherwise just reslice q to q[n:] // then the cost of runtime.growslice can always be less than n/2 func (kcp *KCP) remove_front(q []segment, n int) []segment { if n > cap(q)/2 { newn := copy(q, q[n:]) return q[:newn] } return q[n:] } // Release all cached outgoing segments func (kcp *KCP) ReleaseTX() { for k := range kcp.snd_queue { if kcp.snd_queue[k].data != nil { xmitBuf.Put(kcp.snd_queue[k].data) } } for k := range kcp.snd_buf { if kcp.snd_buf[k].data != nil { xmitBuf.Put(kcp.snd_buf[k].data) } } kcp.snd_queue = nil kcp.snd_buf = nil } kcp-go-5.6.1/kcp_test.go000066400000000000000000000056641374022726700150730ustar00rootroot00000000000000package kcp import ( "io" "net" "sync" "testing" "time" "github.com/xtaci/lossyconn" ) const repeat = 16 func TestLossyConn1(t *testing.T) { t.Log("testing loss rate 10%, rtt 200ms") t.Log("testing link with nodelay parameters:1 10 2 1") client, err := lossyconn.NewLossyConn(0.1, 100) if err != nil { t.Fatal(err) } server, err := lossyconn.NewLossyConn(0.1, 100) if err != nil { t.Fatal(err) } testlink(t, client, server, 1, 10, 2, 1) } func TestLossyConn2(t *testing.T) { t.Log("testing loss rate 20%, rtt 200ms") t.Log("testing link with nodelay parameters:1 10 2 1") client, err := lossyconn.NewLossyConn(0.2, 100) if err != nil { t.Fatal(err) } server, err := lossyconn.NewLossyConn(0.2, 100) if err != nil { t.Fatal(err) } testlink(t, client, server, 1, 10, 2, 1) } func TestLossyConn3(t *testing.T) { t.Log("testing loss rate 30%, rtt 200ms") t.Log("testing link with nodelay parameters:1 10 2 1") client, err := lossyconn.NewLossyConn(0.3, 100) if err != nil { t.Fatal(err) } server, err := lossyconn.NewLossyConn(0.3, 100) if err != nil { t.Fatal(err) } testlink(t, client, server, 1, 10, 2, 1) } func TestLossyConn4(t *testing.T) { t.Log("testing loss rate 10%, rtt 200ms") t.Log("testing link with nodelay parameters:1 10 2 0") client, err := lossyconn.NewLossyConn(0.1, 100) if err != nil { t.Fatal(err) } server, err := lossyconn.NewLossyConn(0.1, 100) if err != nil { t.Fatal(err) } testlink(t, client, server, 1, 10, 2, 0) } func testlink(t *testing.T, client *lossyconn.LossyConn, server *lossyconn.LossyConn, nodelay, interval, resend, nc int) { t.Log("testing with nodelay parameters:", nodelay, interval, resend, nc) sess, _ := NewConn2(server.LocalAddr(), nil, 0, 0, client) listener, _ := ServeConn(nil, 0, 0, server) echoServer := func(l *Listener) { for { conn, err := l.AcceptKCP() if err != nil { return } go func() { conn.SetNoDelay(nodelay, interval, resend, nc) buf := make([]byte, 65536) for { n, err := conn.Read(buf) if err != nil { return } conn.Write(buf[:n]) } }() } } echoTester := func(s *UDPSession, raddr net.Addr) { s.SetNoDelay(nodelay, interval, resend, nc) buf := make([]byte, 64) var rtt time.Duration for i := 0; i < repeat; i++ { start := time.Now() s.Write(buf) io.ReadFull(s, buf) rtt += time.Since(start) } t.Log("client:", client) t.Log("server:", server) t.Log("avg rtt:", rtt/repeat) t.Logf("total time: %v for %v round trip:", rtt, repeat) } go echoServer(listener) echoTester(sess, server.LocalAddr()) } func BenchmarkFlush(b *testing.B) { kcp := NewKCP(1, func(buf []byte, size int) {}) kcp.snd_buf = make([]segment, 1024) for k := range kcp.snd_buf { kcp.snd_buf[k].xmit = 1 kcp.snd_buf[k].resendts = currentMs() + 10000 } b.ResetTimer() b.ReportAllocs() var mu sync.Mutex for i := 0; i < b.N; i++ { mu.Lock() kcp.flush(false) mu.Unlock() } } kcp-go-5.6.1/readloop.go000066400000000000000000000014021374022726700150460ustar00rootroot00000000000000package kcp import ( "sync/atomic" "github.com/pkg/errors" ) func (s *UDPSession) defaultReadLoop() { buf := make([]byte, mtuLimit) var src string for { if n, addr, err := s.conn.ReadFrom(buf); err == nil { // make sure the packet is from the same source if src == "" { // set source address src = addr.String() } else if addr.String() != src { atomic.AddUint64(&DefaultSnmp.InErrs, 1) continue } s.packetInput(buf[:n]) } else { s.notifyReadError(errors.WithStack(err)) return } } } func (l *Listener) defaultMonitor() { buf := make([]byte, mtuLimit) for { if n, from, err := l.conn.ReadFrom(buf); err == nil { l.packetInput(buf[:n], from) } else { l.notifyReadError(errors.WithStack(err)) return } } } kcp-go-5.6.1/readloop_generic.go000066400000000000000000000002161374022726700165440ustar00rootroot00000000000000// +build !linux package kcp func (s *UDPSession) readLoop() { s.defaultReadLoop() } func (l *Listener) monitor() { l.defaultMonitor() } kcp-go-5.6.1/readloop_linux.go000066400000000000000000000046511374022726700162760ustar00rootroot00000000000000// +build linux package kcp import ( "net" "os" "sync/atomic" "github.com/pkg/errors" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) // the read loop for a client session func (s *UDPSession) readLoop() { // default version if s.xconn == nil { s.defaultReadLoop() return } // x/net version var src string msgs := make([]ipv4.Message, batchSize) for k := range msgs { msgs[k].Buffers = [][]byte{make([]byte, mtuLimit)} } for { if count, err := s.xconn.ReadBatch(msgs, 0); err == nil { for i := 0; i < count; i++ { msg := &msgs[i] // make sure the packet is from the same source if src == "" { // set source address if nil src = msg.Addr.String() } else if msg.Addr.String() != src { atomic.AddUint64(&DefaultSnmp.InErrs, 1) continue } // source and size has validated s.packetInput(msg.Buffers[0][:msg.N]) } } else { // compatibility issue: // for linux kernel<=2.6.32, support for sendmmsg is not available // an error of type os.SyscallError will be returned if operr, ok := err.(*net.OpError); ok { if se, ok := operr.Err.(*os.SyscallError); ok { if se.Syscall == "recvmmsg" { s.defaultReadLoop() return } } } s.notifyReadError(errors.WithStack(err)) return } } } // monitor incoming data for all connections of server func (l *Listener) monitor() { var xconn batchConn if _, ok := l.conn.(*net.UDPConn); ok { addr, err := net.ResolveUDPAddr("udp", l.conn.LocalAddr().String()) if err == nil { if addr.IP.To4() != nil { xconn = ipv4.NewPacketConn(l.conn) } else { xconn = ipv6.NewPacketConn(l.conn) } } } // default version if xconn == nil { l.defaultMonitor() return } // x/net version msgs := make([]ipv4.Message, batchSize) for k := range msgs { msgs[k].Buffers = [][]byte{make([]byte, mtuLimit)} } for { if count, err := xconn.ReadBatch(msgs, 0); err == nil { for i := 0; i < count; i++ { msg := &msgs[i] l.packetInput(msg.Buffers[0][:msg.N], msg.Addr) } } else { // compatibility issue: // for linux kernel<=2.6.32, support for sendmmsg is not available // an error of type os.SyscallError will be returned if operr, ok := err.(*net.OpError); ok { if se, ok := operr.Err.(*os.SyscallError); ok { if se.Syscall == "recvmmsg" { l.defaultMonitor() return } } } l.notifyReadError(errors.WithStack(err)) return } } } kcp-go-5.6.1/sess.go000066400000000000000000000703461374022726700142330ustar00rootroot00000000000000// Package kcp-go is a Reliable-UDP library for golang. // // This library intents to provide a smooth, resilient, ordered, // error-checked and anonymous delivery of streams over UDP packets. // // The interfaces of this package aims to be compatible with // net.Conn in standard library, but offers powerful features for advanced users. package kcp import ( "crypto/rand" "encoding/binary" "hash/crc32" "io" "net" "sync" "sync/atomic" "time" "github.com/pkg/errors" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) const ( // 16-bytes nonce for each packet nonceSize = 16 // 4-bytes packet checksum crcSize = 4 // overall crypto header size cryptHeaderSize = nonceSize + crcSize // maximum packet size mtuLimit = 1500 // accept backlog acceptBacklog = 128 ) var ( errInvalidOperation = errors.New("invalid operation") errTimeout = errors.New("timeout") ) var ( // a system-wide packet buffer shared among sending, receiving and FEC // to mitigate high-frequency memory allocation for packets, bytes from xmitBuf // is aligned to 64bit xmitBuf sync.Pool ) func init() { xmitBuf.New = func() interface{} { return make([]byte, mtuLimit) } } type ( // UDPSession defines a KCP session implemented by UDP UDPSession struct { conn net.PacketConn // the underlying packet connection ownConn bool // true if we created conn internally, false if provided by caller kcp *KCP // KCP ARQ protocol l *Listener // pointing to the Listener object if it's been accepted by a Listener block BlockCrypt // block encryption object // kcp receiving is based on packets // recvbuf turns packets into stream recvbuf []byte bufptr []byte // FEC codec fecDecoder *fecDecoder fecEncoder *fecEncoder // settings remote net.Addr // remote peer address rd time.Time // read deadline wd time.Time // write deadline headerSize int // the header size additional to a KCP frame ackNoDelay bool // send ack immediately for each incoming packet(testing purpose) writeDelay bool // delay kcp.flush() for Write() for bulk transfer dup int // duplicate udp packets(testing purpose) // notifications die chan struct{} // notify current session has Closed dieOnce sync.Once chReadEvent chan struct{} // notify Read() can be called without blocking chWriteEvent chan struct{} // notify Write() can be called without blocking // socket error handling socketReadError atomic.Value socketWriteError atomic.Value chSocketReadError chan struct{} chSocketWriteError chan struct{} socketReadErrorOnce sync.Once socketWriteErrorOnce sync.Once // nonce generator nonce Entropy // packets waiting to be sent on wire txqueue []ipv4.Message xconn batchConn // for x/net xconnWriteError error mu sync.Mutex } setReadBuffer interface { SetReadBuffer(bytes int) error } setWriteBuffer interface { SetWriteBuffer(bytes int) error } setDSCP interface { SetDSCP(int) error } ) // newUDPSession create a new udp session for client or server func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn net.PacketConn, ownConn bool, remote net.Addr, block BlockCrypt) *UDPSession { sess := new(UDPSession) sess.die = make(chan struct{}) sess.nonce = new(nonceAES128) sess.nonce.Init() sess.chReadEvent = make(chan struct{}, 1) sess.chWriteEvent = make(chan struct{}, 1) sess.chSocketReadError = make(chan struct{}) sess.chSocketWriteError = make(chan struct{}) sess.remote = remote sess.conn = conn sess.ownConn = ownConn sess.l = l sess.block = block sess.recvbuf = make([]byte, mtuLimit) // cast to writebatch conn if _, ok := conn.(*net.UDPConn); ok { addr, err := net.ResolveUDPAddr("udp", conn.LocalAddr().String()) if err == nil { if addr.IP.To4() != nil { sess.xconn = ipv4.NewPacketConn(conn) } else { sess.xconn = ipv6.NewPacketConn(conn) } } } // FEC codec initialization sess.fecDecoder = newFECDecoder(dataShards, parityShards) if sess.block != nil { sess.fecEncoder = newFECEncoder(dataShards, parityShards, cryptHeaderSize) } else { sess.fecEncoder = newFECEncoder(dataShards, parityShards, 0) } // calculate additional header size introduced by FEC and encryption if sess.block != nil { sess.headerSize += cryptHeaderSize } if sess.fecEncoder != nil { sess.headerSize += fecHeaderSizePlus2 } sess.kcp = NewKCP(conv, func(buf []byte, size int) { if size >= IKCP_OVERHEAD+sess.headerSize { sess.output(buf[:size]) } }) sess.kcp.ReserveBytes(sess.headerSize) if sess.l == nil { // it's a client connection go sess.readLoop() atomic.AddUint64(&DefaultSnmp.ActiveOpens, 1) } else { atomic.AddUint64(&DefaultSnmp.PassiveOpens, 1) } // start per-session updater SystemTimedSched.Put(sess.update, time.Now()) currestab := atomic.AddUint64(&DefaultSnmp.CurrEstab, 1) maxconn := atomic.LoadUint64(&DefaultSnmp.MaxConn) if currestab > maxconn { atomic.CompareAndSwapUint64(&DefaultSnmp.MaxConn, maxconn, currestab) } return sess } // Read implements net.Conn func (s *UDPSession) Read(b []byte) (n int, err error) { for { s.mu.Lock() if len(s.bufptr) > 0 { // copy from buffer into b n = copy(b, s.bufptr) s.bufptr = s.bufptr[n:] s.mu.Unlock() atomic.AddUint64(&DefaultSnmp.BytesReceived, uint64(n)) return n, nil } if size := s.kcp.PeekSize(); size > 0 { // peek data size from kcp if len(b) >= size { // receive data into 'b' directly s.kcp.Recv(b) s.mu.Unlock() atomic.AddUint64(&DefaultSnmp.BytesReceived, uint64(size)) return size, nil } // if necessary resize the stream buffer to guarantee a sufficient buffer space if cap(s.recvbuf) < size { s.recvbuf = make([]byte, size) } // resize the length of recvbuf to correspond to data size s.recvbuf = s.recvbuf[:size] s.kcp.Recv(s.recvbuf) n = copy(b, s.recvbuf) // copy to 'b' s.bufptr = s.recvbuf[n:] // pointer update s.mu.Unlock() atomic.AddUint64(&DefaultSnmp.BytesReceived, uint64(n)) return n, nil } // deadline for current reading operation var timeout *time.Timer var c <-chan time.Time if !s.rd.IsZero() { if time.Now().After(s.rd) { s.mu.Unlock() return 0, errors.WithStack(errTimeout) } delay := time.Until(s.rd) timeout = time.NewTimer(delay) c = timeout.C } s.mu.Unlock() // wait for read event or timeout or error select { case <-s.chReadEvent: if timeout != nil { timeout.Stop() } case <-c: return 0, errors.WithStack(errTimeout) case <-s.chSocketReadError: return 0, s.socketReadError.Load().(error) case <-s.die: return 0, errors.WithStack(io.ErrClosedPipe) } } } // Write implements net.Conn func (s *UDPSession) Write(b []byte) (n int, err error) { return s.WriteBuffers([][]byte{b}) } // WriteBuffers write a vector of byte slices to the underlying connection func (s *UDPSession) WriteBuffers(v [][]byte) (n int, err error) { for { select { case <-s.chSocketWriteError: return 0, s.socketWriteError.Load().(error) case <-s.die: return 0, errors.WithStack(io.ErrClosedPipe) default: } s.mu.Lock() // make sure write do not overflow the max sliding window on both side waitsnd := s.kcp.WaitSnd() if waitsnd < int(s.kcp.snd_wnd) && waitsnd < int(s.kcp.rmt_wnd) { for _, b := range v { n += len(b) for { if len(b) <= int(s.kcp.mss) { s.kcp.Send(b) break } else { s.kcp.Send(b[:s.kcp.mss]) b = b[s.kcp.mss:] } } } waitsnd = s.kcp.WaitSnd() if waitsnd >= int(s.kcp.snd_wnd) || waitsnd >= int(s.kcp.rmt_wnd) || !s.writeDelay { s.kcp.flush(false) s.uncork() } s.mu.Unlock() atomic.AddUint64(&DefaultSnmp.BytesSent, uint64(n)) return n, nil } var timeout *time.Timer var c <-chan time.Time if !s.wd.IsZero() { if time.Now().After(s.wd) { s.mu.Unlock() return 0, errors.WithStack(errTimeout) } delay := time.Until(s.wd) timeout = time.NewTimer(delay) c = timeout.C } s.mu.Unlock() select { case <-s.chWriteEvent: if timeout != nil { timeout.Stop() } case <-c: return 0, errors.WithStack(errTimeout) case <-s.chSocketWriteError: return 0, s.socketWriteError.Load().(error) case <-s.die: return 0, errors.WithStack(io.ErrClosedPipe) } } } // uncork sends data in txqueue if there is any func (s *UDPSession) uncork() { if len(s.txqueue) > 0 { s.tx(s.txqueue) // recycle for k := range s.txqueue { xmitBuf.Put(s.txqueue[k].Buffers[0]) s.txqueue[k].Buffers = nil } s.txqueue = s.txqueue[:0] } } // Close closes the connection. func (s *UDPSession) Close() error { var once bool s.dieOnce.Do(func() { close(s.die) once = true }) if once { atomic.AddUint64(&DefaultSnmp.CurrEstab, ^uint64(0)) // try best to send all queued messages s.mu.Lock() s.kcp.flush(false) s.uncork() // release pending segments s.kcp.ReleaseTX() if s.fecDecoder != nil { s.fecDecoder.release() } s.mu.Unlock() if s.l != nil { // belongs to listener s.l.closeSession(s.remote) return nil } else if s.ownConn { // client socket close return s.conn.Close() } else { return nil } } else { return errors.WithStack(io.ErrClosedPipe) } } // LocalAddr returns the local network address. The Addr returned is shared by all invocations of LocalAddr, so do not modify it. func (s *UDPSession) LocalAddr() net.Addr { return s.conn.LocalAddr() } // RemoteAddr returns the remote network address. The Addr returned is shared by all invocations of RemoteAddr, so do not modify it. func (s *UDPSession) RemoteAddr() net.Addr { return s.remote } // SetDeadline sets the deadline associated with the listener. A zero time value disables the deadline. func (s *UDPSession) SetDeadline(t time.Time) error { s.mu.Lock() defer s.mu.Unlock() s.rd = t s.wd = t s.notifyReadEvent() s.notifyWriteEvent() return nil } // SetReadDeadline implements the Conn SetReadDeadline method. func (s *UDPSession) SetReadDeadline(t time.Time) error { s.mu.Lock() defer s.mu.Unlock() s.rd = t s.notifyReadEvent() return nil } // SetWriteDeadline implements the Conn SetWriteDeadline method. func (s *UDPSession) SetWriteDeadline(t time.Time) error { s.mu.Lock() defer s.mu.Unlock() s.wd = t s.notifyWriteEvent() return nil } // SetWriteDelay delays write for bulk transfer until the next update interval func (s *UDPSession) SetWriteDelay(delay bool) { s.mu.Lock() defer s.mu.Unlock() s.writeDelay = delay } // SetWindowSize set maximum window size func (s *UDPSession) SetWindowSize(sndwnd, rcvwnd int) { s.mu.Lock() defer s.mu.Unlock() s.kcp.WndSize(sndwnd, rcvwnd) } // SetMtu sets the maximum transmission unit(not including UDP header) func (s *UDPSession) SetMtu(mtu int) bool { if mtu > mtuLimit { return false } s.mu.Lock() defer s.mu.Unlock() s.kcp.SetMtu(mtu) return true } // SetStreamMode toggles the stream mode on/off func (s *UDPSession) SetStreamMode(enable bool) { s.mu.Lock() defer s.mu.Unlock() if enable { s.kcp.stream = 1 } else { s.kcp.stream = 0 } } // SetACKNoDelay changes ack flush option, set true to flush ack immediately, func (s *UDPSession) SetACKNoDelay(nodelay bool) { s.mu.Lock() defer s.mu.Unlock() s.ackNoDelay = nodelay } // (deprecated) // // SetDUP duplicates udp packets for kcp output. func (s *UDPSession) SetDUP(dup int) { s.mu.Lock() defer s.mu.Unlock() s.dup = dup } // SetNoDelay calls nodelay() of kcp // https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration func (s *UDPSession) SetNoDelay(nodelay, interval, resend, nc int) { s.mu.Lock() defer s.mu.Unlock() s.kcp.NoDelay(nodelay, interval, resend, nc) } // SetDSCP sets the 6bit DSCP field in IPv4 header, or 8bit Traffic Class in IPv6 header. // // if the underlying connection has implemented `func SetDSCP(int) error`, SetDSCP() will invoke // this function instead. // // It has no effect if it's accepted from Listener. func (s *UDPSession) SetDSCP(dscp int) error { s.mu.Lock() defer s.mu.Unlock() if s.l != nil { return errInvalidOperation } // interface enabled if ts, ok := s.conn.(setDSCP); ok { return ts.SetDSCP(dscp) } if nc, ok := s.conn.(net.Conn); ok { var succeed bool if err := ipv4.NewConn(nc).SetTOS(dscp << 2); err == nil { succeed = true } if err := ipv6.NewConn(nc).SetTrafficClass(dscp); err == nil { succeed = true } if succeed { return nil } } return errInvalidOperation } // SetReadBuffer sets the socket read buffer, no effect if it's accepted from Listener func (s *UDPSession) SetReadBuffer(bytes int) error { s.mu.Lock() defer s.mu.Unlock() if s.l == nil { if nc, ok := s.conn.(setReadBuffer); ok { return nc.SetReadBuffer(bytes) } } return errInvalidOperation } // SetWriteBuffer sets the socket write buffer, no effect if it's accepted from Listener func (s *UDPSession) SetWriteBuffer(bytes int) error { s.mu.Lock() defer s.mu.Unlock() if s.l == nil { if nc, ok := s.conn.(setWriteBuffer); ok { return nc.SetWriteBuffer(bytes) } } return errInvalidOperation } // post-processing for sending a packet from kcp core // steps: // 1. FEC packet generation // 2. CRC32 integrity // 3. Encryption // 4. TxQueue func (s *UDPSession) output(buf []byte) { var ecc [][]byte // 1. FEC encoding if s.fecEncoder != nil { ecc = s.fecEncoder.encode(buf) } // 2&3. crc32 & encryption if s.block != nil { s.nonce.Fill(buf[:nonceSize]) checksum := crc32.ChecksumIEEE(buf[cryptHeaderSize:]) binary.LittleEndian.PutUint32(buf[nonceSize:], checksum) s.block.Encrypt(buf, buf) for k := range ecc { s.nonce.Fill(ecc[k][:nonceSize]) checksum := crc32.ChecksumIEEE(ecc[k][cryptHeaderSize:]) binary.LittleEndian.PutUint32(ecc[k][nonceSize:], checksum) s.block.Encrypt(ecc[k], ecc[k]) } } // 4. TxQueue var msg ipv4.Message for i := 0; i < s.dup+1; i++ { bts := xmitBuf.Get().([]byte)[:len(buf)] copy(bts, buf) msg.Buffers = [][]byte{bts} msg.Addr = s.remote s.txqueue = append(s.txqueue, msg) } for k := range ecc { bts := xmitBuf.Get().([]byte)[:len(ecc[k])] copy(bts, ecc[k]) msg.Buffers = [][]byte{bts} msg.Addr = s.remote s.txqueue = append(s.txqueue, msg) } } // sess update to trigger protocol func (s *UDPSession) update() { select { case <-s.die: default: s.mu.Lock() interval := s.kcp.flush(false) waitsnd := s.kcp.WaitSnd() if waitsnd < int(s.kcp.snd_wnd) && waitsnd < int(s.kcp.rmt_wnd) { s.notifyWriteEvent() } s.uncork() s.mu.Unlock() // self-synchronized timed scheduling SystemTimedSched.Put(s.update, time.Now().Add(time.Duration(interval)*time.Millisecond)) } } // GetConv gets conversation id of a session func (s *UDPSession) GetConv() uint32 { return s.kcp.conv } // GetRTO gets current rto of the session func (s *UDPSession) GetRTO() uint32 { s.mu.Lock() defer s.mu.Unlock() return s.kcp.rx_rto } // GetSRTT gets current srtt of the session func (s *UDPSession) GetSRTT() int32 { s.mu.Lock() defer s.mu.Unlock() return s.kcp.rx_srtt } // GetRTTVar gets current rtt variance of the session func (s *UDPSession) GetSRTTVar() int32 { s.mu.Lock() defer s.mu.Unlock() return s.kcp.rx_rttvar } func (s *UDPSession) notifyReadEvent() { select { case s.chReadEvent <- struct{}{}: default: } } func (s *UDPSession) notifyWriteEvent() { select { case s.chWriteEvent <- struct{}{}: default: } } func (s *UDPSession) notifyReadError(err error) { s.socketReadErrorOnce.Do(func() { s.socketReadError.Store(err) close(s.chSocketReadError) }) } func (s *UDPSession) notifyWriteError(err error) { s.socketWriteErrorOnce.Do(func() { s.socketWriteError.Store(err) close(s.chSocketWriteError) }) } // packet input stage func (s *UDPSession) packetInput(data []byte) { decrypted := false if s.block != nil && len(data) >= cryptHeaderSize { s.block.Decrypt(data, data) data = data[nonceSize:] checksum := crc32.ChecksumIEEE(data[crcSize:]) if checksum == binary.LittleEndian.Uint32(data) { data = data[crcSize:] decrypted = true } else { atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1) } } else if s.block == nil { decrypted = true } if decrypted && len(data) >= IKCP_OVERHEAD { s.kcpInput(data) } } func (s *UDPSession) kcpInput(data []byte) { var kcpInErrors, fecErrs, fecRecovered, fecParityShards uint64 fecFlag := binary.LittleEndian.Uint16(data[4:]) if fecFlag == typeData || fecFlag == typeParity { // 16bit kcp cmd [81-84] and frg [0-255] will not overlap with FEC type 0x00f1 0x00f2 if len(data) >= fecHeaderSizePlus2 { f := fecPacket(data) if f.flag() == typeParity { fecParityShards++ } // lock s.mu.Lock() // if fecDecoder is not initialized, create one with default parameter if s.fecDecoder == nil { s.fecDecoder = newFECDecoder(1, 1) } recovers := s.fecDecoder.decode(f) if f.flag() == typeData { if ret := s.kcp.Input(data[fecHeaderSizePlus2:], true, s.ackNoDelay); ret != 0 { kcpInErrors++ } } for _, r := range recovers { if len(r) >= 2 { // must be larger than 2bytes sz := binary.LittleEndian.Uint16(r) if int(sz) <= len(r) && sz >= 2 { if ret := s.kcp.Input(r[2:sz], false, s.ackNoDelay); ret == 0 { fecRecovered++ } else { kcpInErrors++ } } else { fecErrs++ } } else { fecErrs++ } // recycle the recovers xmitBuf.Put(r) } // to notify the readers to receive the data if n := s.kcp.PeekSize(); n > 0 { s.notifyReadEvent() } // to notify the writers waitsnd := s.kcp.WaitSnd() if waitsnd < int(s.kcp.snd_wnd) && waitsnd < int(s.kcp.rmt_wnd) { s.notifyWriteEvent() } s.uncork() s.mu.Unlock() } else { atomic.AddUint64(&DefaultSnmp.InErrs, 1) } } else { s.mu.Lock() if ret := s.kcp.Input(data, true, s.ackNoDelay); ret != 0 { kcpInErrors++ } if n := s.kcp.PeekSize(); n > 0 { s.notifyReadEvent() } waitsnd := s.kcp.WaitSnd() if waitsnd < int(s.kcp.snd_wnd) && waitsnd < int(s.kcp.rmt_wnd) { s.notifyWriteEvent() } s.uncork() s.mu.Unlock() } atomic.AddUint64(&DefaultSnmp.InPkts, 1) atomic.AddUint64(&DefaultSnmp.InBytes, uint64(len(data))) if fecParityShards > 0 { atomic.AddUint64(&DefaultSnmp.FECParityShards, fecParityShards) } if kcpInErrors > 0 { atomic.AddUint64(&DefaultSnmp.KCPInErrors, kcpInErrors) } if fecErrs > 0 { atomic.AddUint64(&DefaultSnmp.FECErrs, fecErrs) } if fecRecovered > 0 { atomic.AddUint64(&DefaultSnmp.FECRecovered, fecRecovered) } } type ( // Listener defines a server which will be waiting to accept incoming connections Listener struct { block BlockCrypt // block encryption dataShards int // FEC data shard parityShards int // FEC parity shard conn net.PacketConn // the underlying packet connection ownConn bool // true if we created conn internally, false if provided by caller sessions map[string]*UDPSession // all sessions accepted by this Listener sessionLock sync.RWMutex chAccepts chan *UDPSession // Listen() backlog chSessionClosed chan net.Addr // session close queue die chan struct{} // notify the listener has closed dieOnce sync.Once // socket error handling socketReadError atomic.Value chSocketReadError chan struct{} socketReadErrorOnce sync.Once rd atomic.Value // read deadline for Accept() } ) // packet input stage func (l *Listener) packetInput(data []byte, addr net.Addr) { decrypted := false if l.block != nil && len(data) >= cryptHeaderSize { l.block.Decrypt(data, data) data = data[nonceSize:] checksum := crc32.ChecksumIEEE(data[crcSize:]) if checksum == binary.LittleEndian.Uint32(data) { data = data[crcSize:] decrypted = true } else { atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1) } } else if l.block == nil { decrypted = true } if decrypted && len(data) >= IKCP_OVERHEAD { l.sessionLock.RLock() s, ok := l.sessions[addr.String()] l.sessionLock.RUnlock() var conv, sn uint32 convRecovered := false fecFlag := binary.LittleEndian.Uint16(data[4:]) if fecFlag == typeData || fecFlag == typeParity { // 16bit kcp cmd [81-84] and frg [0-255] will not overlap with FEC type 0x00f1 0x00f2 // packet with FEC if fecFlag == typeData && len(data) >= fecHeaderSizePlus2+IKCP_OVERHEAD { conv = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2:]) sn = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2+IKCP_SN_OFFSET:]) convRecovered = true } } else { // packet without FEC conv = binary.LittleEndian.Uint32(data) sn = binary.LittleEndian.Uint32(data[IKCP_SN_OFFSET:]) convRecovered = true } if ok { // existing connection if !convRecovered || conv == s.kcp.conv { // parity data or valid conversation s.kcpInput(data) } else if sn == 0 { // should replace current connection s.Close() s = nil } } if s == nil && convRecovered { // new session if len(l.chAccepts) < cap(l.chAccepts) { // do not let the new sessions overwhelm accept queue s := newUDPSession(conv, l.dataShards, l.parityShards, l, l.conn, false, addr, l.block) s.kcpInput(data) l.sessionLock.Lock() l.sessions[addr.String()] = s l.sessionLock.Unlock() l.chAccepts <- s } } } } func (l *Listener) notifyReadError(err error) { l.socketReadErrorOnce.Do(func() { l.socketReadError.Store(err) close(l.chSocketReadError) // propagate read error to all sessions l.sessionLock.RLock() for _, s := range l.sessions { s.notifyReadError(err) } l.sessionLock.RUnlock() }) } // SetReadBuffer sets the socket read buffer for the Listener func (l *Listener) SetReadBuffer(bytes int) error { if nc, ok := l.conn.(setReadBuffer); ok { return nc.SetReadBuffer(bytes) } return errInvalidOperation } // SetWriteBuffer sets the socket write buffer for the Listener func (l *Listener) SetWriteBuffer(bytes int) error { if nc, ok := l.conn.(setWriteBuffer); ok { return nc.SetWriteBuffer(bytes) } return errInvalidOperation } // SetDSCP sets the 6bit DSCP field in IPv4 header, or 8bit Traffic Class in IPv6 header. // // if the underlying connection has implemented `func SetDSCP(int) error`, SetDSCP() will invoke // this function instead. func (l *Listener) SetDSCP(dscp int) error { // interface enabled if ts, ok := l.conn.(setDSCP); ok { return ts.SetDSCP(dscp) } if nc, ok := l.conn.(net.Conn); ok { var succeed bool if err := ipv4.NewConn(nc).SetTOS(dscp << 2); err == nil { succeed = true } if err := ipv6.NewConn(nc).SetTrafficClass(dscp); err == nil { succeed = true } if succeed { return nil } } return errInvalidOperation } // Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn. func (l *Listener) Accept() (net.Conn, error) { return l.AcceptKCP() } // AcceptKCP accepts a KCP connection func (l *Listener) AcceptKCP() (*UDPSession, error) { var timeout <-chan time.Time if tdeadline, ok := l.rd.Load().(time.Time); ok && !tdeadline.IsZero() { timeout = time.After(time.Until(tdeadline)) } select { case <-timeout: return nil, errors.WithStack(errTimeout) case c := <-l.chAccepts: return c, nil case <-l.chSocketReadError: return nil, l.socketReadError.Load().(error) case <-l.die: return nil, errors.WithStack(io.ErrClosedPipe) } } // SetDeadline sets the deadline associated with the listener. A zero time value disables the deadline. func (l *Listener) SetDeadline(t time.Time) error { l.SetReadDeadline(t) l.SetWriteDeadline(t) return nil } // SetReadDeadline implements the Conn SetReadDeadline method. func (l *Listener) SetReadDeadline(t time.Time) error { l.rd.Store(t) return nil } // SetWriteDeadline implements the Conn SetWriteDeadline method. func (l *Listener) SetWriteDeadline(t time.Time) error { return errInvalidOperation } // Close stops listening on the UDP address, and closes the socket func (l *Listener) Close() error { var once bool l.dieOnce.Do(func() { close(l.die) once = true }) var err error if once { if l.ownConn { err = l.conn.Close() } } else { err = errors.WithStack(io.ErrClosedPipe) } return err } // closeSession notify the listener that a session has closed func (l *Listener) closeSession(remote net.Addr) (ret bool) { l.sessionLock.Lock() defer l.sessionLock.Unlock() if _, ok := l.sessions[remote.String()]; ok { delete(l.sessions, remote.String()) return true } return false } // Addr returns the listener's network address, The Addr returned is shared by all invocations of Addr, so do not modify it. func (l *Listener) Addr() net.Addr { return l.conn.LocalAddr() } // Listen listens for incoming KCP packets addressed to the local address laddr on the network "udp", func Listen(laddr string) (net.Listener, error) { return ListenWithOptions(laddr, nil, 0, 0) } // ListenWithOptions listens for incoming KCP packets addressed to the local address laddr on the network "udp" with packet encryption. // // 'block' is the block encryption algorithm to encrypt packets. // // 'dataShards', 'parityShards' specify how many parity packets will be generated following the data packets. // // Check https://github.com/klauspost/reedsolomon for details func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards int) (*Listener, error) { udpaddr, err := net.ResolveUDPAddr("udp", laddr) if err != nil { return nil, errors.WithStack(err) } conn, err := net.ListenUDP("udp", udpaddr) if err != nil { return nil, errors.WithStack(err) } return serveConn(block, dataShards, parityShards, conn, true) } // ServeConn serves KCP protocol for a single packet connection. func ServeConn(block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*Listener, error) { return serveConn(block, dataShards, parityShards, conn, false) } func serveConn(block BlockCrypt, dataShards, parityShards int, conn net.PacketConn, ownConn bool) (*Listener, error) { l := new(Listener) l.conn = conn l.ownConn = ownConn l.sessions = make(map[string]*UDPSession) l.chAccepts = make(chan *UDPSession, acceptBacklog) l.chSessionClosed = make(chan net.Addr) l.die = make(chan struct{}) l.dataShards = dataShards l.parityShards = parityShards l.block = block l.chSocketReadError = make(chan struct{}) go l.monitor() return l, nil } // Dial connects to the remote address "raddr" on the network "udp" without encryption and FEC func Dial(raddr string) (net.Conn, error) { return DialWithOptions(raddr, nil, 0, 0) } // DialWithOptions connects to the remote address "raddr" on the network "udp" with packet encryption // // 'block' is the block encryption algorithm to encrypt packets. // // 'dataShards', 'parityShards' specify how many parity packets will be generated following the data packets. // // Check https://github.com/klauspost/reedsolomon for details func DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards int) (*UDPSession, error) { // network type detection udpaddr, err := net.ResolveUDPAddr("udp", raddr) if err != nil { return nil, errors.WithStack(err) } network := "udp4" if udpaddr.IP.To4() == nil { network = "udp" } conn, err := net.ListenUDP(network, nil) if err != nil { return nil, errors.WithStack(err) } var convid uint32 binary.Read(rand.Reader, binary.LittleEndian, &convid) return newUDPSession(convid, dataShards, parityShards, nil, conn, true, udpaddr, block), nil } // NewConn3 establishes a session and talks KCP protocol over a packet connection. func NewConn3(convid uint32, raddr net.Addr, block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*UDPSession, error) { return newUDPSession(convid, dataShards, parityShards, nil, conn, false, raddr, block), nil } // NewConn2 establishes a session and talks KCP protocol over a packet connection. func NewConn2(raddr net.Addr, block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*UDPSession, error) { var convid uint32 binary.Read(rand.Reader, binary.LittleEndian, &convid) return NewConn3(convid, raddr, block, dataShards, parityShards, conn) } // NewConn establishes a session and talks KCP protocol over a packet connection. func NewConn(raddr string, block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*UDPSession, error) { udpaddr, err := net.ResolveUDPAddr("udp", raddr) if err != nil { return nil, errors.WithStack(err) } return NewConn2(udpaddr, block, dataShards, parityShards, conn) } kcp-go-5.6.1/sess_test.go000066400000000000000000000344121374022726700152640ustar00rootroot00000000000000package kcp import ( "crypto/sha1" "fmt" "io" "log" "net" "net/http" _ "net/http/pprof" "sync" "sync/atomic" "testing" "time" "golang.org/x/crypto/pbkdf2" ) var baseport = uint32(10000) var key = []byte("testkey") var pass = pbkdf2.Key(key, []byte("testsalt"), 4096, 32, sha1.New) func init() { go func() { log.Println(http.ListenAndServe("0.0.0.0:6060", nil)) }() log.Println("beginning tests, encryption:salsa20, fec:10/3") } func dialEcho(port int) (*UDPSession, error) { //block, _ := NewNoneBlockCrypt(pass) //block, _ := NewSimpleXORBlockCrypt(pass) //block, _ := NewTEABlockCrypt(pass[:16]) //block, _ := NewAESBlockCrypt(pass) block, _ := NewSalsa20BlockCrypt(pass) sess, err := DialWithOptions(fmt.Sprintf("127.0.0.1:%v", port), block, 10, 3) if err != nil { panic(err) } sess.SetStreamMode(true) sess.SetStreamMode(false) sess.SetStreamMode(true) sess.SetWindowSize(1024, 1024) sess.SetReadBuffer(16 * 1024 * 1024) sess.SetWriteBuffer(16 * 1024 * 1024) sess.SetStreamMode(true) sess.SetNoDelay(1, 10, 2, 1) sess.SetMtu(1400) sess.SetMtu(1600) sess.SetMtu(1400) sess.SetACKNoDelay(true) sess.SetACKNoDelay(false) sess.SetDeadline(time.Now().Add(time.Minute)) return sess, err } func dialSink(port int) (*UDPSession, error) { sess, err := DialWithOptions(fmt.Sprintf("127.0.0.1:%v", port), nil, 0, 0) if err != nil { panic(err) } sess.SetStreamMode(true) sess.SetWindowSize(1024, 1024) sess.SetReadBuffer(16 * 1024 * 1024) sess.SetWriteBuffer(16 * 1024 * 1024) sess.SetStreamMode(true) sess.SetNoDelay(1, 10, 2, 1) sess.SetMtu(1400) sess.SetACKNoDelay(false) sess.SetDeadline(time.Now().Add(time.Minute)) return sess, err } func dialTinyBufferEcho(port int) (*UDPSession, error) { //block, _ := NewNoneBlockCrypt(pass) //block, _ := NewSimpleXORBlockCrypt(pass) //block, _ := NewTEABlockCrypt(pass[:16]) //block, _ := NewAESBlockCrypt(pass) block, _ := NewSalsa20BlockCrypt(pass) sess, err := DialWithOptions(fmt.Sprintf("127.0.0.1:%v", port), block, 10, 3) if err != nil { panic(err) } return sess, err } ////////////////////////// func listenEcho(port int) (net.Listener, error) { //block, _ := NewNoneBlockCrypt(pass) //block, _ := NewSimpleXORBlockCrypt(pass) //block, _ := NewTEABlockCrypt(pass[:16]) //block, _ := NewAESBlockCrypt(pass) block, _ := NewSalsa20BlockCrypt(pass) return ListenWithOptions(fmt.Sprintf("127.0.0.1:%v", port), block, 10, 0) } func listenTinyBufferEcho(port int) (net.Listener, error) { //block, _ := NewNoneBlockCrypt(pass) //block, _ := NewSimpleXORBlockCrypt(pass) //block, _ := NewTEABlockCrypt(pass[:16]) //block, _ := NewAESBlockCrypt(pass) block, _ := NewSalsa20BlockCrypt(pass) return ListenWithOptions(fmt.Sprintf("127.0.0.1:%v", port), block, 10, 3) } func listenSink(port int) (net.Listener, error) { return ListenWithOptions(fmt.Sprintf("127.0.0.1:%v", port), nil, 0, 0) } func echoServer(port int) net.Listener { l, err := listenEcho(port) if err != nil { panic(err) } go func() { kcplistener := l.(*Listener) kcplistener.SetReadBuffer(4 * 1024 * 1024) kcplistener.SetWriteBuffer(4 * 1024 * 1024) kcplistener.SetDSCP(46) for { s, err := l.Accept() if err != nil { return } // coverage test s.(*UDPSession).SetReadBuffer(4 * 1024 * 1024) s.(*UDPSession).SetWriteBuffer(4 * 1024 * 1024) go handleEcho(s.(*UDPSession)) } }() return l } func sinkServer(port int) net.Listener { l, err := listenSink(port) if err != nil { panic(err) } go func() { kcplistener := l.(*Listener) kcplistener.SetReadBuffer(4 * 1024 * 1024) kcplistener.SetWriteBuffer(4 * 1024 * 1024) kcplistener.SetDSCP(46) for { s, err := l.Accept() if err != nil { return } go handleSink(s.(*UDPSession)) } }() return l } func tinyBufferEchoServer(port int) net.Listener { l, err := listenTinyBufferEcho(port) if err != nil { panic(err) } go func() { for { s, err := l.Accept() if err != nil { return } go handleTinyBufferEcho(s.(*UDPSession)) } }() return l } /////////////////////////// func handleEcho(conn *UDPSession) { conn.SetStreamMode(true) conn.SetWindowSize(4096, 4096) conn.SetNoDelay(1, 10, 2, 1) conn.SetDSCP(46) conn.SetMtu(1400) conn.SetACKNoDelay(false) conn.SetReadDeadline(time.Now().Add(time.Hour)) conn.SetWriteDeadline(time.Now().Add(time.Hour)) buf := make([]byte, 65536) for { n, err := conn.Read(buf) if err != nil { return } conn.Write(buf[:n]) } } func handleSink(conn *UDPSession) { conn.SetStreamMode(true) conn.SetWindowSize(4096, 4096) conn.SetNoDelay(1, 10, 2, 1) conn.SetDSCP(46) conn.SetMtu(1400) conn.SetACKNoDelay(false) conn.SetReadDeadline(time.Now().Add(time.Hour)) conn.SetWriteDeadline(time.Now().Add(time.Hour)) buf := make([]byte, 65536) for { _, err := conn.Read(buf) if err != nil { return } } } func handleTinyBufferEcho(conn *UDPSession) { conn.SetStreamMode(true) buf := make([]byte, 2) for { n, err := conn.Read(buf) if err != nil { return } conn.Write(buf[:n]) } } /////////////////////////// func TestTimeout(t *testing.T) { port := int(atomic.AddUint32(&baseport, 1)) l := echoServer(port) defer l.Close() cli, err := dialEcho(port) if err != nil { panic(err) } buf := make([]byte, 10) //timeout cli.SetDeadline(time.Now().Add(time.Second)) <-time.After(2 * time.Second) n, err := cli.Read(buf) if n != 0 || err == nil { t.Fail() } cli.Close() } func TestSendRecv(t *testing.T) { port := int(atomic.AddUint32(&baseport, 1)) l := echoServer(port) defer l.Close() cli, err := dialEcho(port) if err != nil { panic(err) } cli.SetWriteDelay(true) cli.SetDUP(1) const N = 100 buf := make([]byte, 10) for i := 0; i < N; i++ { msg := fmt.Sprintf("hello%v", i) cli.Write([]byte(msg)) if n, err := cli.Read(buf); err == nil { if string(buf[:n]) != msg { t.Fail() } } else { panic(err) } } cli.Close() } func TestSendVector(t *testing.T) { port := int(atomic.AddUint32(&baseport, 1)) l := echoServer(port) defer l.Close() cli, err := dialEcho(port) if err != nil { panic(err) } cli.SetWriteDelay(false) const N = 100 buf := make([]byte, 20) v := make([][]byte, 2) for i := 0; i < N; i++ { v[0] = []byte(fmt.Sprintf("hello%v", i)) v[1] = []byte(fmt.Sprintf("world%v", i)) msg := fmt.Sprintf("hello%vworld%v", i, i) cli.WriteBuffers(v) if n, err := cli.Read(buf); err == nil { if string(buf[:n]) != msg { t.Error(string(buf[:n]), msg) } } else { panic(err) } } cli.Close() } func TestTinyBufferReceiver(t *testing.T) { port := int(atomic.AddUint32(&baseport, 1)) l := tinyBufferEchoServer(port) defer l.Close() cli, err := dialTinyBufferEcho(port) if err != nil { panic(err) } const N = 100 snd := byte(0) fillBuffer := func(buf []byte) { for i := 0; i < len(buf); i++ { buf[i] = snd snd++ } } rcv := byte(0) check := func(buf []byte) bool { for i := 0; i < len(buf); i++ { if buf[i] != rcv { return false } rcv++ } return true } sndbuf := make([]byte, 7) rcvbuf := make([]byte, 7) for i := 0; i < N; i++ { fillBuffer(sndbuf) cli.Write(sndbuf) if n, err := io.ReadFull(cli, rcvbuf); err == nil { if !check(rcvbuf[:n]) { t.Fail() } } else { panic(err) } } cli.Close() } func TestClose(t *testing.T) { var n int var err error port := int(atomic.AddUint32(&baseport, 1)) l := echoServer(port) defer l.Close() cli, err := dialEcho(port) if err != nil { panic(err) } // double close cli.Close() if cli.Close() == nil { t.Fatal("double close misbehavior") } // write after close buf := make([]byte, 10) n, err = cli.Write(buf) if n != 0 || err == nil { t.Fatal("write after close misbehavior") } // write, close, read, read cli, err = dialEcho(port) if err != nil { panic(err) } if n, err = cli.Write(buf); err != nil { t.Fatal("write misbehavior") } // wait until data arrival time.Sleep(2 * time.Second) // drain cli.Close() n, err = io.ReadFull(cli, buf) if err != nil { t.Fatal("closed conn drain bytes failed", err, n) } // after drain, read should return error n, err = cli.Read(buf) if n != 0 || err == nil { t.Fatal("write->close->drain->read misbehavior", err, n) } cli.Close() } func TestParallel1024CLIENT_64BMSG_64CNT(t *testing.T) { port := int(atomic.AddUint32(&baseport, 1)) l := echoServer(port) defer l.Close() var wg sync.WaitGroup wg.Add(1024) for i := 0; i < 1024; i++ { go parallel_client(&wg, port) } wg.Wait() } func parallel_client(wg *sync.WaitGroup, port int) (err error) { cli, err := dialEcho(port) if err != nil { panic(err) } err = echo_tester(cli, 64, 64) cli.Close() wg.Done() return } func BenchmarkEchoSpeed4K(b *testing.B) { speedclient(b, 4096) } func BenchmarkEchoSpeed64K(b *testing.B) { speedclient(b, 65536) } func BenchmarkEchoSpeed512K(b *testing.B) { speedclient(b, 524288) } func BenchmarkEchoSpeed1M(b *testing.B) { speedclient(b, 1048576) } func speedclient(b *testing.B, nbytes int) { port := int(atomic.AddUint32(&baseport, 1)) l := echoServer(port) defer l.Close() b.ReportAllocs() cli, err := dialEcho(port) if err != nil { panic(err) } if err := echo_tester(cli, nbytes, b.N); err != nil { b.Fail() } b.SetBytes(int64(nbytes)) cli.Close() } func BenchmarkSinkSpeed4K(b *testing.B) { sinkclient(b, 4096) } func BenchmarkSinkSpeed64K(b *testing.B) { sinkclient(b, 65536) } func BenchmarkSinkSpeed256K(b *testing.B) { sinkclient(b, 524288) } func BenchmarkSinkSpeed1M(b *testing.B) { sinkclient(b, 1048576) } func sinkclient(b *testing.B, nbytes int) { port := int(atomic.AddUint32(&baseport, 1)) l := sinkServer(port) defer l.Close() b.ReportAllocs() cli, err := dialSink(port) if err != nil { panic(err) } sink_tester(cli, nbytes, b.N) b.SetBytes(int64(nbytes)) cli.Close() } func echo_tester(cli net.Conn, msglen, msgcount int) error { buf := make([]byte, msglen) for i := 0; i < msgcount; i++ { // send packet if _, err := cli.Write(buf); err != nil { return err } // receive packet nrecv := 0 for { n, err := cli.Read(buf) if err != nil { return err } else { nrecv += n if nrecv == msglen { break } } } } return nil } func sink_tester(cli *UDPSession, msglen, msgcount int) error { // sender buf := make([]byte, msglen) for i := 0; i < msgcount; i++ { if _, err := cli.Write(buf); err != nil { return err } } return nil } func TestSNMP(t *testing.T) { t.Log(DefaultSnmp.Copy()) t.Log(DefaultSnmp.Header()) t.Log(DefaultSnmp.ToSlice()) DefaultSnmp.Reset() t.Log(DefaultSnmp.ToSlice()) } func TestListenerClose(t *testing.T) { port := int(atomic.AddUint32(&baseport, 1)) l, err := ListenWithOptions(fmt.Sprintf("127.0.0.1:%v", port), nil, 10, 3) if err != nil { t.Fail() } l.SetReadDeadline(time.Now().Add(time.Second)) l.SetWriteDeadline(time.Now().Add(time.Second)) l.SetDeadline(time.Now().Add(time.Second)) time.Sleep(2 * time.Second) if _, err := l.Accept(); err == nil { t.Fail() } l.Close() fakeaddr, _ := net.ResolveUDPAddr("udp6", "127.0.0.1:1111") if l.closeSession(fakeaddr) { t.Fail() } } // A wrapper for net.PacketConn that remembers when Close has been called. type closedFlagPacketConn struct { net.PacketConn Closed bool } func (c *closedFlagPacketConn) Close() error { c.Closed = true return c.PacketConn.Close() } func newClosedFlagPacketConn(c net.PacketConn) *closedFlagPacketConn { return &closedFlagPacketConn{c, false} } // Listener should close a net.PacketConn that it created. // https://github.com/xtaci/kcp-go/issues/165 func TestListenerOwnedPacketConn(t *testing.T) { // ListenWithOptions creates its own net.PacketConn. l, err := ListenWithOptions("127.0.0.1:0", nil, 0, 0) if err != nil { panic(err) } defer l.Close() // Replace the internal net.PacketConn with one that remembers when it // has been closed. pconn := newClosedFlagPacketConn(l.conn) l.conn = pconn if pconn.Closed { t.Fatal("owned PacketConn closed before Listener.Close()") } err = l.Close() if err != nil { panic(err) } if !pconn.Closed { t.Fatal("owned PacketConn not closed after Listener.Close()") } } // Listener should not close a net.PacketConn that it did not create. // https://github.com/xtaci/kcp-go/issues/165 func TestListenerNonOwnedPacketConn(t *testing.T) { // Create a net.PacketConn not owned by the Listener. c, err := net.ListenPacket("udp", "127.0.0.1:0") if err != nil { panic(err) } defer c.Close() // Make it remember when it has been closed. pconn := newClosedFlagPacketConn(c) l, err := ServeConn(nil, 0, 0, pconn) if err != nil { panic(err) } defer l.Close() if pconn.Closed { t.Fatal("non-owned PacketConn closed before Listener.Close()") } err = l.Close() if err != nil { panic(err) } if pconn.Closed { t.Fatal("non-owned PacketConn closed after Listener.Close()") } } // UDPSession should close a net.PacketConn that it created. // https://github.com/xtaci/kcp-go/issues/165 func TestUDPSessionOwnedPacketConn(t *testing.T) { l := sinkServer(0) defer l.Close() // DialWithOptions creates its own net.PacketConn. client, err := DialWithOptions(l.Addr().String(), nil, 0, 0) if err != nil { panic(err) } defer client.Close() // Replace the internal net.PacketConn with one that remembers when it // has been closed. pconn := newClosedFlagPacketConn(client.conn) client.conn = pconn if pconn.Closed { t.Fatal("owned PacketConn closed before UDPSession.Close()") } err = client.Close() if err != nil { panic(err) } if !pconn.Closed { t.Fatal("owned PacketConn not closed after UDPSession.Close()") } } // UDPSession should not close a net.PacketConn that it did not create. // https://github.com/xtaci/kcp-go/issues/165 func TestUDPSessionNonOwnedPacketConn(t *testing.T) { l := sinkServer(0) defer l.Close() // Create a net.PacketConn not owned by the UDPSession. c, err := net.ListenPacket("udp", "127.0.0.1:0") if err != nil { panic(err) } defer c.Close() // Make it remember when it has been closed. pconn := newClosedFlagPacketConn(c) client, err := NewConn2(l.Addr(), nil, 0, 0, pconn) if err != nil { panic(err) } defer client.Close() if pconn.Closed { t.Fatal("non-owned PacketConn closed before UDPSession.Close()") } err = client.Close() if err != nil { panic(err) } if pconn.Closed { t.Fatal("non-owned PacketConn closed after UDPSession.Close()") } } kcp-go-5.6.1/snmp.go000066400000000000000000000122711374022726700142240ustar00rootroot00000000000000package kcp import ( "fmt" "sync/atomic" ) // Snmp defines network statistics indicator type Snmp struct { BytesSent uint64 // bytes sent from upper level BytesReceived uint64 // bytes received to upper level MaxConn uint64 // max number of connections ever reached ActiveOpens uint64 // accumulated active open connections PassiveOpens uint64 // accumulated passive open connections CurrEstab uint64 // current number of established connections InErrs uint64 // UDP read errors reported from net.PacketConn InCsumErrors uint64 // checksum errors from CRC32 KCPInErrors uint64 // packet iput errors reported from KCP InPkts uint64 // incoming packets count OutPkts uint64 // outgoing packets count InSegs uint64 // incoming KCP segments OutSegs uint64 // outgoing KCP segments InBytes uint64 // UDP bytes received OutBytes uint64 // UDP bytes sent RetransSegs uint64 // accmulated retransmited segments FastRetransSegs uint64 // accmulated fast retransmitted segments EarlyRetransSegs uint64 // accmulated early retransmitted segments LostSegs uint64 // number of segs inferred as lost RepeatSegs uint64 // number of segs duplicated FECRecovered uint64 // correct packets recovered from FEC FECErrs uint64 // incorrect packets recovered from FEC FECParityShards uint64 // FEC segments received FECShortShards uint64 // number of data shards that's not enough for recovery } func newSnmp() *Snmp { return new(Snmp) } // Header returns all field names func (s *Snmp) Header() []string { return []string{ "BytesSent", "BytesReceived", "MaxConn", "ActiveOpens", "PassiveOpens", "CurrEstab", "InErrs", "InCsumErrors", "KCPInErrors", "InPkts", "OutPkts", "InSegs", "OutSegs", "InBytes", "OutBytes", "RetransSegs", "FastRetransSegs", "EarlyRetransSegs", "LostSegs", "RepeatSegs", "FECParityShards", "FECErrs", "FECRecovered", "FECShortShards", } } // ToSlice returns current snmp info as slice func (s *Snmp) ToSlice() []string { snmp := s.Copy() return []string{ fmt.Sprint(snmp.BytesSent), fmt.Sprint(snmp.BytesReceived), fmt.Sprint(snmp.MaxConn), fmt.Sprint(snmp.ActiveOpens), fmt.Sprint(snmp.PassiveOpens), fmt.Sprint(snmp.CurrEstab), fmt.Sprint(snmp.InErrs), fmt.Sprint(snmp.InCsumErrors), fmt.Sprint(snmp.KCPInErrors), fmt.Sprint(snmp.InPkts), fmt.Sprint(snmp.OutPkts), fmt.Sprint(snmp.InSegs), fmt.Sprint(snmp.OutSegs), fmt.Sprint(snmp.InBytes), fmt.Sprint(snmp.OutBytes), fmt.Sprint(snmp.RetransSegs), fmt.Sprint(snmp.FastRetransSegs), fmt.Sprint(snmp.EarlyRetransSegs), fmt.Sprint(snmp.LostSegs), fmt.Sprint(snmp.RepeatSegs), fmt.Sprint(snmp.FECParityShards), fmt.Sprint(snmp.FECErrs), fmt.Sprint(snmp.FECRecovered), fmt.Sprint(snmp.FECShortShards), } } // Copy make a copy of current snmp snapshot func (s *Snmp) Copy() *Snmp { d := newSnmp() d.BytesSent = atomic.LoadUint64(&s.BytesSent) d.BytesReceived = atomic.LoadUint64(&s.BytesReceived) d.MaxConn = atomic.LoadUint64(&s.MaxConn) d.ActiveOpens = atomic.LoadUint64(&s.ActiveOpens) d.PassiveOpens = atomic.LoadUint64(&s.PassiveOpens) d.CurrEstab = atomic.LoadUint64(&s.CurrEstab) d.InErrs = atomic.LoadUint64(&s.InErrs) d.InCsumErrors = atomic.LoadUint64(&s.InCsumErrors) d.KCPInErrors = atomic.LoadUint64(&s.KCPInErrors) d.InPkts = atomic.LoadUint64(&s.InPkts) d.OutPkts = atomic.LoadUint64(&s.OutPkts) d.InSegs = atomic.LoadUint64(&s.InSegs) d.OutSegs = atomic.LoadUint64(&s.OutSegs) d.InBytes = atomic.LoadUint64(&s.InBytes) d.OutBytes = atomic.LoadUint64(&s.OutBytes) d.RetransSegs = atomic.LoadUint64(&s.RetransSegs) d.FastRetransSegs = atomic.LoadUint64(&s.FastRetransSegs) d.EarlyRetransSegs = atomic.LoadUint64(&s.EarlyRetransSegs) d.LostSegs = atomic.LoadUint64(&s.LostSegs) d.RepeatSegs = atomic.LoadUint64(&s.RepeatSegs) d.FECParityShards = atomic.LoadUint64(&s.FECParityShards) d.FECErrs = atomic.LoadUint64(&s.FECErrs) d.FECRecovered = atomic.LoadUint64(&s.FECRecovered) d.FECShortShards = atomic.LoadUint64(&s.FECShortShards) return d } // Reset values to zero func (s *Snmp) Reset() { atomic.StoreUint64(&s.BytesSent, 0) atomic.StoreUint64(&s.BytesReceived, 0) atomic.StoreUint64(&s.MaxConn, 0) atomic.StoreUint64(&s.ActiveOpens, 0) atomic.StoreUint64(&s.PassiveOpens, 0) atomic.StoreUint64(&s.CurrEstab, 0) atomic.StoreUint64(&s.InErrs, 0) atomic.StoreUint64(&s.InCsumErrors, 0) atomic.StoreUint64(&s.KCPInErrors, 0) atomic.StoreUint64(&s.InPkts, 0) atomic.StoreUint64(&s.OutPkts, 0) atomic.StoreUint64(&s.InSegs, 0) atomic.StoreUint64(&s.OutSegs, 0) atomic.StoreUint64(&s.InBytes, 0) atomic.StoreUint64(&s.OutBytes, 0) atomic.StoreUint64(&s.RetransSegs, 0) atomic.StoreUint64(&s.FastRetransSegs, 0) atomic.StoreUint64(&s.EarlyRetransSegs, 0) atomic.StoreUint64(&s.LostSegs, 0) atomic.StoreUint64(&s.RepeatSegs, 0) atomic.StoreUint64(&s.FECParityShards, 0) atomic.StoreUint64(&s.FECErrs, 0) atomic.StoreUint64(&s.FECRecovered, 0) atomic.StoreUint64(&s.FECShortShards, 0) } // DefaultSnmp is the global KCP connection statistics collector var DefaultSnmp *Snmp func init() { DefaultSnmp = newSnmp() } kcp-go-5.6.1/timedsched.go000066400000000000000000000064241374022726700153630ustar00rootroot00000000000000package kcp import ( "container/heap" "runtime" "sync" "time" ) // SystemTimedSched is the library level timed-scheduler var SystemTimedSched *TimedSched = NewTimedSched(runtime.NumCPU()) type timedFunc struct { execute func() ts time.Time } // a heap for sorted timed function type timedFuncHeap []timedFunc func (h timedFuncHeap) Len() int { return len(h) } func (h timedFuncHeap) Less(i, j int) bool { return h[i].ts.Before(h[j].ts) } func (h timedFuncHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *timedFuncHeap) Push(x interface{}) { *h = append(*h, x.(timedFunc)) } func (h *timedFuncHeap) Pop() interface{} { old := *h n := len(old) x := old[n-1] old[n-1].execute = nil // avoid memory leak *h = old[0 : n-1] return x } // TimedSched represents the control struct for timed parallel scheduler type TimedSched struct { // prepending tasks prependTasks []timedFunc prependLock sync.Mutex chPrependNotify chan struct{} // tasks will be distributed through chTask chTask chan timedFunc dieOnce sync.Once die chan struct{} } // NewTimedSched creates a parallel-scheduler with given parallelization func NewTimedSched(parallel int) *TimedSched { ts := new(TimedSched) ts.chTask = make(chan timedFunc) ts.die = make(chan struct{}) ts.chPrependNotify = make(chan struct{}, 1) for i := 0; i < parallel; i++ { go ts.sched() } go ts.prepend() return ts } func (ts *TimedSched) sched() { var tasks timedFuncHeap timer := time.NewTimer(0) drained := false for { select { case task := <-ts.chTask: now := time.Now() if now.After(task.ts) { // already delayed! execute immediately task.execute() } else { heap.Push(&tasks, task) // properly reset timer to trigger based on the top element stopped := timer.Stop() if !stopped && !drained { <-timer.C } timer.Reset(tasks[0].ts.Sub(now)) drained = false } case now := <-timer.C: drained = true for tasks.Len() > 0 { if now.After(tasks[0].ts) { heap.Pop(&tasks).(timedFunc).execute() } else { timer.Reset(tasks[0].ts.Sub(now)) drained = false break } } case <-ts.die: return } } } func (ts *TimedSched) prepend() { var tasks []timedFunc for { select { case <-ts.chPrependNotify: ts.prependLock.Lock() // keep cap to reuse slice if cap(tasks) < cap(ts.prependTasks) { tasks = make([]timedFunc, 0, cap(ts.prependTasks)) } tasks = tasks[:len(ts.prependTasks)] copy(tasks, ts.prependTasks) for k := range ts.prependTasks { ts.prependTasks[k].execute = nil // avoid memory leak } ts.prependTasks = ts.prependTasks[:0] ts.prependLock.Unlock() for k := range tasks { select { case ts.chTask <- tasks[k]: tasks[k].execute = nil // avoid memory leak case <-ts.die: return } } tasks = tasks[:0] case <-ts.die: return } } } // Put a function 'f' awaiting to be executed at 'deadline' func (ts *TimedSched) Put(f func(), deadline time.Time) { ts.prependLock.Lock() ts.prependTasks = append(ts.prependTasks, timedFunc{f, deadline}) ts.prependLock.Unlock() select { case ts.chPrependNotify <- struct{}{}: default: } } // Close terminates this scheduler func (ts *TimedSched) Close() { ts.dieOnce.Do(func() { close(ts.die) }) } kcp-go-5.6.1/tx.go000066400000000000000000000007571374022726700137100ustar00rootroot00000000000000package kcp import ( "sync/atomic" "github.com/pkg/errors" "golang.org/x/net/ipv4" ) func (s *UDPSession) defaultTx(txqueue []ipv4.Message) { nbytes := 0 npkts := 0 for k := range txqueue { if n, err := s.conn.WriteTo(txqueue[k].Buffers[0], txqueue[k].Addr); err == nil { nbytes += n npkts++ } else { s.notifyWriteError(errors.WithStack(err)) break } } atomic.AddUint64(&DefaultSnmp.OutPkts, uint64(npkts)) atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes)) } kcp-go-5.6.1/tx_generic.go000066400000000000000000000002161374022726700153720ustar00rootroot00000000000000// +build !linux package kcp import ( "golang.org/x/net/ipv4" ) func (s *UDPSession) tx(txqueue []ipv4.Message) { s.defaultTx(txqueue) } kcp-go-5.6.1/tx_linux.go000066400000000000000000000020661374022726700151220ustar00rootroot00000000000000// +build linux package kcp import ( "net" "os" "sync/atomic" "github.com/pkg/errors" "golang.org/x/net/ipv4" ) func (s *UDPSession) tx(txqueue []ipv4.Message) { // default version if s.xconn == nil || s.xconnWriteError != nil { s.defaultTx(txqueue) return } // x/net version nbytes := 0 npkts := 0 for len(txqueue) > 0 { if n, err := s.xconn.WriteBatch(txqueue, 0); err == nil { for k := range txqueue[:n] { nbytes += len(txqueue[k].Buffers[0]) } npkts += n txqueue = txqueue[n:] } else { // compatibility issue: // for linux kernel<=2.6.32, support for sendmmsg is not available // an error of type os.SyscallError will be returned if operr, ok := err.(*net.OpError); ok { if se, ok := operr.Err.(*os.SyscallError); ok { if se.Syscall == "sendmmsg" { s.xconnWriteError = se s.defaultTx(txqueue) return } } } s.notifyWriteError(errors.WithStack(err)) break } } atomic.AddUint64(&DefaultSnmp.OutPkts, uint64(npkts)) atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes)) } kcp-go-5.6.1/wechat_donate.jpg000066400000000000000000001047531374022726700162360ustar00rootroot00000000000000JFIFC  % !###&)&")"#"C """""""""""""""""""""""""""""""""""""""""""""""""""  r(D2q À۞$??:qbmL!;#hqL@"0d} |d,*  L #&ɀ2(2:d\J# 9QL (0Jö+RO"yO`ʍ)%%U؀fqL6KLL` pDc'tɀ'8m#FLDXI&bμ Ӄ'>\g > (`Y1qS -b\A* E_أ!D W6:CqB0Ge ,ZDjح 'R.|$;c+p{ Nb LGD8VP iaEG  T卛"I#r ofH ##E@(T==(ҕ}dL$VPڝa"-E<&tdPViGnh +u (è=NP`PTK}O0ꕰsDn<ɀ:c`qL):B) 2hN,1:& Uv .x1s a[GYс\'Ry98LZ9&'XX+P>}Iȉ*Ѭ*#VF|0T 7%FE+\`[ `~W#},Bl`|ܮgǜ~@[?svVY&Ȋ8s`2-< ˛As4N0?JmHWORDJ]pw&?ZΘ^KYZwշ|^ގ^Ʊ!#'8,yI?C#fzMpC+vI|_J-4$zWeiQ+mn8?:\DUZ;AZXlƧ~-<К4XОW)-$ -ZD̸a!R@0}nSgk,ir;C7PhtAa7CdAd 3&0rHTڒy & p@HpuǐXrgE.~=l>_Ʒk65WeZÎ6E|#uF`XGp𑀲!!4%"m+@nxPh@ '\UwM-3\z9}GؗO5lw{|:Zvl̑ aĕ3#(i 8Ҧ7fp{-"F`W%mtcg[]y$Pz(Y SsYm%BUPV%dE~rIgPNCؒp\Qk3mk[K 2X  z,ՕwBI 3%Yg?}$y2.2XnK}B+-8djGO2yXB|BaNȈF`Lj b|?,}lD{`}O дsn @xl:10oM !ؚr4'Xȕ`06uOWaܑkv4ee1 >EcF@& 0NyI _岋p02"͜/q4d0i0`cgVj%xKzO ,\|kJ}0~Y0AogB%pΏPfܖd ҷKU$ 4CI[^L`T=XՌHʀϙbuNCS2iP{O(;:*d,uV03zmO+|TQ@a&Q+ت'ҭ éS2 'd!R҅Ox2`ɒI4){ 5ŗ|G0X`>@hGM$V-Px`UfDk8(Ҙ$^"?c"!q>GИ 0IÊ$@J'ٓ AQ7D(L'FHPV@Ѝ*djp%Hܒȧ܎;C0`,UF 90@#*iDpWn@iJD-PȬBt &a4A2rs܍_xAT P{FTJcJYÄ;$ D%"NrmdM)_J :" rĜ  xab&*ؒ l'$|B>HhoƀaGVw #a{& X VXjeodZ\ز 䧡rAj"U-CDsrExIf4VW-L,BFҲmG̲OԲpuz?s`s *dbN $LDeÈy .xi%ग़a !A?i&B)-@,SԞz%PsZ2X;`'Qȸ!B0T0 R8='qL6nJLˇZ>'sFnK{> [Y1Vdd!E2ޏ[$$d`|IZdL`Tcf䬣 @Cd0&dv 3xX dh@g̊dI| 9aq2L]8Y@d s1.$$ceDi 8R@K'LhM9WhNfH>g4h2Xٹ+0-ZDĸ0d *X >@K'^M",`Y9`\0o~iTcdDM&%ĀabJ;C+j DG,,yЍ]49#ȸS#g#CtZp2:ĸ`]"&+\$ :dq#˜p2Gqۏ%*`ɐ>Mqv%ɓZYI7*IJbpQ.N,Й!$`90L9`:<' vF!;3h978 60!1253AQ#4@%&B`pMN2x<18s3<18s3<1nn^ݭ5/,i.ycqd9yCqd9yA@xmI(ʂXma8#Eɮ#w!TJX`:o91S.7HuʺTq+, &-_Q3b=R~hbĜAΖl(A%Hn5ȍiex 龀fOGlM{| &K~kSw^ݤX7i E! onkWJ}y~݈ 0d`Exӄз3;i=;m_7AᚽT@^\2ǸŁơq^!qg*^bG oIrAsj~2;v]~ħѷ G؀ɮ]-qf_'8L z8^x9=Hɖ%wDӸX_J.[+T8%/lT±<3XJr4Cq,(.bq|W(Tqv<}j}}.{K֯ 9!pc2ڈ/m)FJh&u%+ϑ{0ˢ߆1vF|1R&qtpx Maf_'8?/"{(yM~2ʷ<{*OY +0 #ljm"P gQ\K!}T캐iCCx2E@)?d :f[@E+fyzj_c4K9>1S. oIrAw䊞2;v]~ħѷ F؀ɮP< h0zd`F pkzx6~4u%CCn9Tu<=@R' :5.EZ~^׸awGD1SM{| %KUj ULy*J}>'~^1֯ؔ63jF=,z2`db)i8>8!N >lд<~̢2ncT߽]vZ}0z*`.DO?8fUPEگJzʐ1*c֔@dbZ&-Cʖ~dfw}WMZU|[Z+ 8rugX7b{%n oIrGk㮾=0z*`.VKzVvmjOo>>N\to |7o_\\ƚZo k5!2Ƃ]ɻ|eEwA`H ]r2a }Ʀ:W2_]ZR_Z{v|b%sqq̛r+8>@=jhHvHG#ꋩ554DO"hA}JCv4Ohz$mנ\>RT|/_7|o|i.ZbKtJ[ ~@w_/? ; 7m *AMnłsC@hNٸWZ$@6c˼ EkLg}c(Ր}Ski,)1Df\vM-:bj/pƤɧkyZZ("yH@WnE-[ 7{ijk1]vH.4zĒ Y\2eU%ixpFsFI~@w? <x^ ~Awq q/%uLn 5I؇=s$4n5z!xeq+_,X? hA="QdaYoGőq e2A kĞݓR`DJ$=Hx0,7# 9^W_?bO=&iƑx#SkWJbX~c:Exp̏b57 qѼՋW*DNjg7bkVⰮkbM^JčCL47#H$bݑQ)PU>ʉ)FwөBeKk!Wpn",DHeUQru&5* coĦ6)\UGx*oCсV/HMiZ,UhǛw%@銞]@&#`L{\m~: $ݻʃ&(4߃}K=6mx#&OTL,u5KlHiY VSiöH !'P duZVjjV Ԙ'eD7)+)W'j͎3FH:6#ue)ƭhr5SzG[`^J݁Ӷ{FiT;c|\DEC.JheF{ABNN0(d[y9NI8TCdʅ/V2Fv/4uoѣ1biy}985j^F`wdܴ H n17>|2~$ tJRk8l6<&d84gv|DMa2>shJ $1.I:F}{VRXRǎ$h6&qףD<\IAU`C_%[F ޱzO+s)鍊bԆR*n1Fw&\?k&rtq~_S\FL zĞ݈ ?@]2fP ~ۚHӄ+Ӆ!$q?d}aۢᄽIrmBP߃{qؑ_# cښDM⊾?m?J5e1OeQ;jt*/-x$YHgJ艭Hm>oLIr)Vp, esdYsG W=Ɓ!@L'6_ÛOࠢq]FZu,ƷưM.ۜ#|o2c4ڣ{mQY̶¢ |M{p1rLbr'l6HVCYrSG{M`x5ұn6KkvZ7oT1]/ N-#N}|]#dpDϘ-\9fSaM\4D#D(ܲo<-_fQ}ڮ5]v״>WMx /ZVؙ+9Mٸ13<C]pr }J֊\0o+h1;4S_Z؟{zq7Qa^F7DEtm5xbqi<5oO_lUzߗPj%?p4W foZ&Oڮ7(=0dY`ZT?b(J[5W n5+JcTǬH驭`Ϣ 5}6>\#-kj[UyDR *J|M{%C;uIGzy\*ݽz7RjrexZttS& "pKMTLP1'Ϊ~׭)TDD۩WɃDjfgZH#&Ov-Ve-$;mafGdې MJ KV7/ 5 H$7+~!XRhq)lkKOHF@+˵ۖIeFRo%m9tٗ5Z)";oKNhiuT!P+j5arՉw­94eZSqM%'8kCFh)/!zU%|f)̔F_ikccd `} -Y?RZ 71meꌌI }8} CNW9aNhG3ؠ,M~XLiʊܷfら9]zQ@Ww[ƨ.'=Ғu(%5kHkcLzQy#UrKXMjWU,_-Y滘آ ڪRYR$ qgM,WSA^Ŋ Jwve]?m5$Mۻs[Vb6zx"^Xx),0sA2e[ BgBl⇹bh1G4%Xn DgsA9 dVH-?36!&3/ALokl9EspV0wn G5jZk-QA5."w<GM[&d}S(Ę4BPQY[ǬoIpS#q̌[gޭIB})E558]l6sgqL!e) yi\\>m@q1nK'3*mꩯZ[ ]dƆj*UQ].&R\hZUúQ/YHnxWwprsmL}I"F of8 .m6< /k!̬Auѳl6 "2)Tfb$[*:%gnJ%QQܔR&63h ;(4vDjK(H#GW]̸ItJ{nehMt产qucYY"7kfb> vۥa>[fY&nJ*F䢑(nJ)FAJLk4jVgFFUE.Qٷb4(^әvƿL Б.1[:X*)(Zyu ,cl J(^_qd<`uXhDGM#7Ϋ,,x6*J+H:5R/sAZ޳RcI܌R7%:>8☒Y]g}y~݈ 4,f?Bp`tɬ3>"/[k։HZ?r5\Ηzޠ%os<~)M%,gZ(hu7p- )]DVU]AqFp28j0v?bnCN9vϻ z,4JiŖN')m) V+)ˍ@2\RPH$]'6n@+ ymv]xG=zκpFV:QU+r٦6,6 #mQHTR6I;)%e'ε+m{Mu4Uݻa V)^޻Im^,$pe$c ںNt8j7?oGp11>pJY & Bpt./)jT^۱C_{Ȳ2I㶸KrcmJrί-Ueg XmqHTT6:وq19TnNV;U ,}jJƁw۸y :ruv) +dz>LtV c#N988L%{%0^V&ۨFtDݞIa&cJBed{%&B=Z%Wߪ:-Sr:*WVW:yyj֔?*jjf6SeɣZJ*E$up'^Tp>o( XN-IQ`s_36"֝+k)6 XGP+Nn]XlJ=.Ram|ǟe95pQuH#~4膺Ĩ]A4{ ')> \Q5>4?玴kdZq{~ ? $#9a۪ӆu-8?fqf6>#Dnܿ-I"U /bJn =ֵ5lj %To}ErAaW(nre+3 m3=䌖*05 %3VqK#El9& 09-&kkZ(1C!QEs凜ԂA2O0qɆ Dbn}$o$?17LNb~1ܦ%F8"#Ra-0a͝tE( iM5XMLY3o__ؼjAoFQ Jj6l^kiЮ ?1@2B,pyq#CԇGR/2O˩ۚмtPE R~=9Xzj;ht`CUAav&J vHz:u!C]-Ȕ_8B]d 83&!FjeS,ڪXMڿkK4=y]ƪ)O *ŋ^5Sviӌ5^F<d} #ZBnE!5ib6д2hEm}{W]r@sGZ/ڽBд>M:Q9aۚAYʨkB 3:4tc/mo)m4KLk )dI%?̊Pb|WF`l6H$l)#&L^n)jX~CT?ֲBaɞ{nq@۠om7 IڍHCZ*K]nžpq\@de~[؆lc{q8om!٩&. ?%0 ISM5\s:K(fqU J75쑰_&k%ƼTM[W_߆xM{qiO1d%FAFdtҫ_x2h$u*jSauN]IqSvg}FA͐OHԨkoN7xiV#Gd޼sI;ZH*>1hn+)2R%,XDL*cDڲ<6+ J >oGKs1PR73"A\eٓZJ˓sPb"OJʌruhmVe٥aiXmVXfBi>g^rH'̒imVf*5ilբ$33(zw&qtqh2kfn Pމo aF,Wd8=ٛzKԗ/cCO H]*)ۊANRIh zgt4 5W?$FQPbavL zx@ d←۬V$UɋF\Vƛݢ:HneTNݏτ/x:;ΰ]ǖ;oIHq+D.\QފHR"XO05 "6'v$22Ty XqWFRƃ!fGBpXHnn.Ujˍ|ƖeAPbsLuV4Vw۬Vl:MiYyd~u*n*T#U7T Τ C8aˈ)c +vu$ yo$w .̐6s#Kͷ$ )NxƈCPwа sՁ/#Wtpa=m?ljR`\lI-nwT[jH㘎.!lI,gʭfc*GN U5+cU\Í#V.jIÎY^sV#ȉD%ve϶^US܂a$Gdq lG:9|hGxѸr m}Ԑ!Cn{~lu5;v!}0˭٭D4ejNO½8RGWr GU5 #S?C;>D9xaG0#O!7s 9}kD)AMn;@^BrQrzIX6'Z.Q@D7nA#]D{AT@^<2˸qơp{z ?EK\V-rn®5;}azUv^Cl#BwAɞTʞ׆'a{:"İʸ!8=BKi "Vv޵];dO>F2_cK;46 n!wXfU =`HOp,Uzơ/ }/U5 #Tvb(zҮKC>{]xA~ԧѷ HԀv݋Zܽ Փ'WNUM44#~)k̮' -||19c"۵iʻ8t@YfCרA˕>*뮚S&HXSZTIXTI߻ˉW oH|43~h3$RF֧ewUw1V ]VN=]8T[ĥNpTJ2WtXO6f9hD6XMZkK=G^|1b&{rsP>CP`Ͱ3{ЋH~}[Oy)Q{u4]N{֍5N2q!+׆DPiVi2ᦺ}MGԨ}JyRiu:xi=}5ħѷ G؀ɮ]tL7: O ^D$xiNji͏awoa |^QϟvMfb3p\w=;Đ=% 9qS>,Pl^#'h N,Rܷ $K풗 oY YENXcYX}/]JJ 66P톔@' y|孓4,Dd͔=v`2GDoSφ#@dnN: qfo'8J)Cd5d)*o˧ָa[^v5S|9~Md®I1S>+TfKf\<ݏś٢p=j͎P#UFQʒLsz>Yu4/`c z%ӥTyWT\S\d{vlYzk)UFϳ)mv 2o'G67S5ǎQDi8?dS>9t fX8~{pA_۪O!q0f  Qu>b?nkA_LX6 ŃiQ`L!a% y<0#|)ՖQ)XmVX7`tc|}pbu~^pd^}T.ct1Î$t$$ {]9?,'*oL~ .CsPtMJ6])&upibu$=yX{BHJl2zď0u@QV,5.mL-uE!JwG|4x?f3W\p{dۆ*vͮ6E?@ܲcW YM8"c!Șr*2"!Ȩr*2|kf%ur*3"!Ȩr&2"!Ȩ$$BG,hH&Td9֍M8[I2Ș %5ѭ%vJy 6bV\j\"!Șr&2cmZQ!1U QT"0ARS$2aq#Br%345s&@Cb`pt ?Hͫkʪk{'Zַq5Mk{'Zַq5Mk{'ZfeğWS[ma%Zkj_sV^1j?sV{kg>>1PQ+[&˪B&Jty-OuŖkZLrਾmt䃱*K=Zkj,)\s3(vHQd=8OQj@Ҳ^d؞m}rC-i櫿i# E`"?j͌Dz!>2[ըw"Cxd=SgK{C~o &PkM5I[-l$Oe" WO_% Yz[/"Zmxǹ*Ŷ@+ֽ{{@IbG5W{sV^1jK=Zkj_sUX þ`{;W[=O6I:*?r*?rJ4A I׽H{~$ Eи{PbcI ]jX8@kT}e7[V"4m)[D5t9Fn[Ҳf -ݖK[ yaTFh² g M2DJۨ*K8#O# v>{FKֽjǷLŐ0m4&S+dyE7`Og4 Zn1VBH})UYzC TVHL㶭Qt8;CF-AkP!A&`vNɁ0iLN#r!`vw*Ge~&X]gU]gS? Ղ'ZV}͞~c>hyoě{ ynPwblN՝ʯO%Ϳ^'=o{/g{O4v{Ӟ5;Wv91Ҽq ? Q ֵ2:ll@qʭq ʑSIS/N`WV2}}G<૔ :37 rDk_A[apUʣʟoD9ByF@bB¢g/ή3>9~urW)A~u;u".Hn2qAcr3_@DQRU`zq?u~}OJlMES?R}.-BIV|8T6 8Oo{O4v[᪯ [ eCuAOWvcysJf ;Ӭ,n֊g^JMqZ)=y+Eǯ%hb g\s)%]ޯyoě;|ҮcdzMeGfj4z>]]HVzu w|hu!JqOV0쒮~=3gۢ֊kKVH9Z-!F7jc^t:njc w;+sgJJK"f WU$c'Vz,dk٦BzC˧Y_V@I-8}:LfVq_ص^J!ǯ%hzVk^JAǯ%i62gnl?4㯻i 䌕"V-{kܵ/^+Z-i[׹kJ_ZRZҷr֕.{E$7[s[;;|ҧb37F ǝ$CL֫2g/VÈ c%$ *!RXqaY-v&+Ӕ :`ueam.;*#w٦of 0"XT]̀&danS3ZBun{DFJ U/^ إrWbi:1A.QDۮk"%-~\-\Ya!8w';S xZZfI71:54`/h +ڊ%nhZM%Dii[׹kSY[yiIQSz$ho73"#kmݦE68u25bÊ,?p6i"NVNy'\Փ.jj55dW iÇ+z{˶2R̤y4ɦ*R[[k'Ne}vJ(v'>g6Ѓh;쓮1QQ89&Tei)4o;︮%'-Knq))=EU-;wYQ(CBҰa, 5dWpXypٕb;̖T*GAiHwêlFahyUUYrی+N +gt2Nξխi9RBUXog>޺;>r\uYkꠝhjѓ|գ'6FOmVN\I1[;ɹqn7'"AE2'6͇P9NT +3W/zz0e'Phjѓ\`nn"S\'R!9Z46B]M'2d AO3Zqs.8b"ѳ|jz)Joc:1>75L8@y-k8Zp?Hm<(`^^{0nLֲg9Zs-k8Zp?~9kNʹo3\k$/k:ȷEDѼ@ێ]l9Zs-k8Z5>[yumsJgױ4v{kw=^ ynlPw`mOWܙ/<5ޫM}4)5֛HI൥{;sfN (dX"U.++;;TTNԭ.[ǣۡ7ѰUw]NXS{L!PT %I&TthsX}  }jxTgguUxYm7{; iiԶ17w7TdT -j΂4684"Q6wd(jؓ ˦]Zd \^ G#O|T%jYT|+<}YTVv<g͈>5Y HvDl@ȲILmȞ;g-ⴰqosV)j$3PbDƛps"֖)jŽZtcς:;2y-Ud7ˬSp4づ|m>3=: '٣(Pp}Ȯyᱻb:ʻ/A!G#|v;vBe1 DZzӷe~Kf[ ō5'qwiZA>̖`[` Ȯ͟c>hʷPPWRsTpy߄n8MvI)F#+";J/&s[k Ȋ+n Z67Pc@*,FmW+ mqG >/Z67Z67Z27ZRĨu@b He櫬˓\弮.:0{f!b4"ֲVTeL}w}R3_jժɆJ`ԶQBeoND++u yKM4e7`\'5 moj487Y bUmCp܈4D>Te~R3\*N &P{Reoeoeo]o 9F؎W=HW;W[,w)cUbE~v|q0h[//Oj7v aJ8+my d`+SYˢ}@\ydcM~ p_8l_W?6_u4ɺp>H׻HaSei1&oum!& RUmQ<5GGdMJ;a71V =4 [ A yrG;R9I|,4]FFqVQKbɒJM:usl:vMR&~U#v_O8)V@"c?4cGQps$AyUtL%j۪mBGy2Un?*ܸż1܍/ Q(Rֳ=GdC_u1sK=խ&Im"$sL;N+ZMyw >g}kEB˒kڧ#QtXW:ZMy蔑p8Q#7EWqSN\Ic+U˔v(0izK MHZ$DD~嫜+%>>,c h`R[ŧ]H1qŔ`,Skeޔ0#ֹw0y(- ER=ƗprƟ~"ړ\Y릈*fX_ԠeJO,~!z距:O_Ci]ow Acמ2OvC`Jt/s}X=$\-J;w19(`VA aa3IQf=l2 Φ` $\c+]m:묗S갨 $\v.Q; T|oQ1MADJqN E?ﮤw/Pᤲ&f" }zK!pٕ\{bVF̈*^zH1R+[_Yn6F`rI ;hg{;75R<w=<4]iJpWO4fvD>04`vR0^p_60Gt"I;^^}lsRIc=6q{]JFGJ9iWJn͟m#/SW/[hs&o8CL}դ^C F,)uz׮$tt(arhJlq/sTtn *+Ptt^FH~Zg TZl/sS}h LL"}j 0ȍ77©ZQp2>"֫g{o30R,`0$=i68I=ZM!znκfGw`p+K2.{r߭PQ!l2]@+Ne+J1ĽZM%z,I1a̼`3_]/2,fb6]Zlq/sr4lBlpϬeZJկS^}j=kVП3+@FC3T&5i68I1=ZU}ngӻځ- A7UhYlkIkV?óZJrޙ"g[%O 9/|s]|]fO~H}oWy^oH*! M_hH  )Q*.{SRYT(S2?xpp*5}{TqVUDaK?%h39w8yWym~$@DimA%LKb]uL=Ddi'G='fx3nzҒIAi@-}X/J}@/%-^J GzHcy%{;^yoƛ;]dzܣ+~yJbe=nNl^?CzMwblp\ooFvRy$o{9e ۍ89TTVp U, F#4T*c5q@*VqUtNI6(:"?jQPWu~lI>iU ´72EZJɐo(H=JUo{E6,iME:X$6jb@Iب4|D~L@pR,C> k 5k 5_⍩Fe3ﷳIXyR38 {UWE8V1~xVw #ZR쇣6np[R2Qʪ;V-IFnWx1 p]$b*X-vˬ&iO0XI+Y_9X9QݧC5E&$3TU٥ekdy@fdQӳeV~  ]Pccj3 (H{;|\moEEd[/nGj2ݶGFU :;qldeP$Z2waj 2%ih4iSR8Dug4ֈ?߇e͖Z6gPo -@W((V| 7]ք'}>֔:K+Dxz7Z"+E^>EKT;[%y:Y@>o iQfA/n5zb1<¹Zie!MZd89kFOブȧs#0vjHZf#(֤9+~Ql<ubPo2e7kYO?et'Cs֍%hprձp3)c.؈AL W:t!'ɻ>|π_ 74îTT h edu>>̗XL LUg/ʭ>~Un |_Gyʘ(挿 y.ڝCSU :㰌_"?5pƥ2'ZN!l1xjS]U^/V*U_/ʀ4zGU1͝LJapďT HlsB=jDD?48 @O;WT*>?PQSav Jlg?U}S$Ob-t) Sm4~Y_ӮcM+3Mi4?4량i?w9yײsZqNA~)4~h? SAiW6wKPEWMg{9 )Us;W[,v2>f +&yl=no8٤$iH2SzM5ZSyMVT~U~~|CfHb%Y3՚&YrQy߶:p a(qZ^]-f֖|gkKY3ڷDۮt@"'AZi7>-Uu!w:׼eWY?E(թ.οj AVuoik7vQ"[TSpjcp ^c _ o? @ Kۙ$x[B*oi{7vdTO)B td&iK,I!ndϑZ𚨌C<0,593WZG5/? w^{ej}x٬C;o*{QSԴN+_WR$DkH38.`E oL4{G*Ei4Q X,pZ:kb43,&W^*yF`u N9n6];D`2u{|լ{|ysV7̠m\,6{Hc8VF)МNUT:4@~KikYX8S29M404v-w:H_M $>ƚYK>jgUm~ɖn4 f^D ;.O*V=6=ӷ[}MeȲJZѷZ6eDQn@/ ss$b 793.D4ʭk+5BmeKHhGR ]-xAS6`o16G40<. ;W^'vvwyCܣyu=ߖ޿ n_86%O&}o$vK}Nsݎl? "ڕ5yHJ=1o)b1%pTnF=}Em'۞GGxwڔvn Y_Jm^ZdP^x8 dӏI&6uQx;7X53ǵW4sEFs/{3Q{ ynPެXVpO%;ؿ]Ԟh;|v/0D&+YMrUΜ; c(ڕa|Gy0DbyCWw̐cֲg;5WW24n7+.a6%<*V^V dAE$UǨlA9mĕxHE!Ѱ+Ɓ[0l DGOqՎ72f-vXJb)pkNƶ\)0eU+XMr'\^A}" a;:N,V^IV dE, 4#A֎];_i/(NwٿZk?5mSniWTP&Nd0cRJmeUe;5ZwkW_xL׵zL'\iT9Z-k) ZS~\x~paWP~FPm_ +GAnUt'WIU1ZqÂn0v%k)߁ZsnRQޙK'($Z;'vN-y(K0uõ$Q8*;'vN1y+ ,9M,4;s;)Gdגů%otq Lo;gᴈh0K6C+vn\^ ^5_K aWc~JA̐*%^ZGt[fo$6574vN-y)XYs +$%)%YP8z(oNzDbg JX8{vn4ޏcHMvguS5o ;*m6kyERy *p ZՎyZ/=kV8jXs&2k^߉6wZ]Ǐf9-oҬc;dӣ}j`;xJFQ;ZӧnVbe#)cfyB R/]?Mq&$/w;5+PKM@8ޭL Hj vl%Xп|JKzrVe,ozZ뷹rͽcY^XTK9(ѝ&7*W;Z-uwҵ&7=5Ҽ0hEzSz5-guTb7f/d1q1a͵ IOJm.9>iS5REU^GdgŧP%ќ4[%h"Ը n"L4ʗb8h9tU%:3揫Qz IdKkxa(.]rer "LC*ylFc;qv9v=εo]DL0̶)v!c8};-lHekY8B/b7] eIT+F_*crğj-ч D4Biaۭia㛫DKl3욋b%ΰev}ɂa" HZX8KRaɹm>d TQvERѦ9q#y@Ivj eQ.HJ>*֪J aFeDE~c>hyoĞ<6;c{~W.O%͞ρ=N5ݿm'*gxRG+gt:&kyEߤKGAPUe:ҭ*?:ܫl<bdi rO%{ԏWOVlF5!ݶWAI os7|k̷!&_5ѳV»<OGDu]$*,$B|.><l1>5,0'L?Qیa/+ pW(Qϟx79z$gvї§jU&al~DTI0.~\`+ev)0(M̪ն[gSN5nF@"R^yzׁ*4Ma M NSSOmMmaQLw5Ҽ{H#ZexyL/5i:WjaN)&kζ^XA_V52mX.?e?q:<֡G΀,5Φ.D2li%ܟum=% VxUJ=Z8Gkz4u'tJ7?oiɸ^b |&®ӄN#ܵ)%_RQʊz3ڕ./>Ƀ;ByZ ųZaxyаJwdp<3*F WTsPL{{kQc.шg]J=RU^zsJ+Խ}+/Ik+3 ]K}wc>G^z{=կ WIsJlyL&Dxz6^MeDxz^EeDYxzvq0\,;ERVPonovMeDYxz^MeDxz^Qf;)%Z\JRCyh7e֒+{}Hʃ(u2. Z&*0-*G8U\WisÝ#M 2l= mv"'bU⢋+$7kDxz6^EeDٸzt|QeUW U(P!1 "A2#3Q?klzo˟iL @zR aEѲLd.l9=IȁxCpՔF& 9ae dӏ3 S=W'|r[^ 0}l`$!"P1A3?6ZӾqA5'(kS1 RAY+/>N $$+!w,^(D|dwU;ԙ{ݑ|$ @ cRܹEB&(*姼hax/G`HYٶRƯ'~h zxD9"Z)N8fP㔨PeH@>F!#'!3qZm|)PZVzva= w2-WmJMLa#gOXdz3 ^Xcdk1GgUc8iTNɏي LOS*fNo6'-nu=asz?QQ߶W(:~L@u\0M{o~F?}