pax_global_header00006660000000000000000000000064135230132240014505gustar00rootroot0000000000000052 comment=46b7e4617752b40523d3698cf6a685b90bb73f22 kcp-go-5.4.4/000077500000000000000000000000001352301322400126775ustar00rootroot00000000000000kcp-go-5.4.4/.gitignore000066400000000000000000000004121352301322400146640ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # 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.4.4/.travis.yml000066400000000000000000000004331352301322400150100ustar00rootroot00000000000000language: go go: - 1.9.x - 1.10.x - 1.11.x before_install: - go get -t -v ./... install: - go get github.com/xtaci/kcp-go script: - go test -coverprofile=coverage.txt -covermode=atomic -bench . after_success: - bash <(curl -s https://codecov.io/bash) kcp-go-5.4.4/LICENSE000066400000000000000000000020651352301322400137070ustar00rootroot00000000000000The 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.4.4/README.md000066400000000000000000000336531352301322400141700ustar00rootroot00000000000000kcp-go [![GoDoc][1]][2] [![Powered][9]][10] [![MIT licensed][11]][12] [![Build Status][3]][4] [![Go Report Card][5]][6] [![Coverage Statusd][7]][8] [1]: https://godoc.org/github.com/xtaci/kcp-go?status.svg [2]: https://godoc.org/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 ## 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 ``` ## 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/libkcp -- FEC enhanced KCP session library for iOS/Android in C++ 2. https://github.com/skywind3000/kcp -- A Fast and Reliable ARQ Protocol 3. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go kcp-go-5.4.4/batchconn.go000066400000000000000000000003221352301322400151620ustar00rootroot00000000000000package 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.4.4/crypt.go000066400000000000000000000454221352301322400143760ustar00rootroot00000000000000package kcp import ( "crypto/aes" "crypto/cipher" "crypto/des" "crypto/sha1" "github.com/templexxx/xor" "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 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: encryptVariant(block, dst, src, buf) } } // 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 for i := 0; i < repeat; i++ { s := src[base:][0:64] d := dst[base:][0:64] // 1 xor.BytesSrc1(d[0:8], s[0:8], tbl) block.Encrypt(tbl, d[0:8]) // 2 xor.BytesSrc1(d[8:16], s[8:16], tbl) block.Encrypt(tbl, d[8:16]) // 3 xor.BytesSrc1(d[16:24], s[16:24], tbl) block.Encrypt(tbl, d[16:24]) // 4 xor.BytesSrc1(d[24:32], s[24:32], tbl) block.Encrypt(tbl, d[24:32]) // 5 xor.BytesSrc1(d[32:40], s[32:40], tbl) block.Encrypt(tbl, d[32:40]) // 6 xor.BytesSrc1(d[40:48], s[40:48], tbl) block.Encrypt(tbl, d[40:48]) // 7 xor.BytesSrc1(d[48:56], s[48:56], tbl) block.Encrypt(tbl, d[48:56]) // 8 xor.BytesSrc1(d[56:64], s[56:64], tbl) block.Encrypt(tbl, d[56:64]) base += 64 } switch left { case 7: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 6: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 5: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 4: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 3: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 2: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 1: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 8 fallthrough case 0: xor.BytesSrc0(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.BytesSrc1(d[0:16], s[0:16], tbl) block.Encrypt(tbl, d[0:16]) // 2 xor.BytesSrc1(d[16:32], s[16:32], tbl) block.Encrypt(tbl, d[16:32]) // 3 xor.BytesSrc1(d[32:48], s[32:48], tbl) block.Encrypt(tbl, d[32:48]) // 4 xor.BytesSrc1(d[48:64], s[48:64], tbl) block.Encrypt(tbl, d[48:64]) // 5 xor.BytesSrc1(d[64:80], s[64:80], tbl) block.Encrypt(tbl, d[64:80]) // 6 xor.BytesSrc1(d[80:96], s[80:96], tbl) block.Encrypt(tbl, d[80:96]) // 7 xor.BytesSrc1(d[96:112], s[96:112], tbl) block.Encrypt(tbl, d[96:112]) // 8 xor.BytesSrc1(d[112:128], s[112:128], tbl) block.Encrypt(tbl, d[112:128]) base += 128 } switch left { case 7: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 6: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 5: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 4: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 3: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 2: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 1: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += 16 fallthrough case 0: xor.BytesSrc0(dst[base:], src[base:], tbl) } } func encryptVariant(block cipher.Block, dst, src, buf []byte) { blocksize := block.BlockSize() tbl := buf[:blocksize] block.Encrypt(tbl, initialVector) n := len(src) / blocksize base := 0 repeat := n / 8 left := n % 8 for i := 0; i < repeat; i++ { // 1 xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize // 2 xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize // 3 xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize // 4 xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize // 5 xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize // 6 xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize // 7 xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize // 8 xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize } switch left { case 7: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize fallthrough case 6: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize fallthrough case 5: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize fallthrough case 4: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize fallthrough case 3: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize fallthrough case 2: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize fallthrough case 1: xor.BytesSrc1(dst[base:], src[base:], tbl) block.Encrypt(tbl, dst[base:]) base += blocksize fallthrough case 0: xor.BytesSrc0(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: decryptVariant(block, dst, src, buf) } } 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 for i := 0; i < repeat; i++ { s := src[base:][0:64] d := dst[base:][0:64] // 1 block.Encrypt(next, s[0:8]) xor.BytesSrc1(d[0:8], s[0:8], tbl) // 2 block.Encrypt(tbl, s[8:16]) xor.BytesSrc1(d[8:16], s[8:16], next) // 3 block.Encrypt(next, s[16:24]) xor.BytesSrc1(d[16:24], s[16:24], tbl) // 4 block.Encrypt(tbl, s[24:32]) xor.BytesSrc1(d[24:32], s[24:32], next) // 5 block.Encrypt(next, s[32:40]) xor.BytesSrc1(d[32:40], s[32:40], tbl) // 6 block.Encrypt(tbl, s[40:48]) xor.BytesSrc1(d[40:48], s[40:48], next) // 7 block.Encrypt(next, s[48:56]) xor.BytesSrc1(d[48:56], s[48:56], tbl) // 8 block.Encrypt(tbl, s[56:64]) xor.BytesSrc1(d[56:64], s[56:64], next) base += 64 } switch left { case 7: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 8 fallthrough case 6: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 8 fallthrough case 5: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 8 fallthrough case 4: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 8 fallthrough case 3: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 8 fallthrough case 2: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 8 fallthrough case 1: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 8 fallthrough case 0: xor.BytesSrc0(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.BytesSrc1(d[0:16], s[0:16], tbl) // 2 block.Encrypt(tbl, s[16:32]) xor.BytesSrc1(d[16:32], s[16:32], next) // 3 block.Encrypt(next, s[32:48]) xor.BytesSrc1(d[32:48], s[32:48], tbl) // 4 block.Encrypt(tbl, s[48:64]) xor.BytesSrc1(d[48:64], s[48:64], next) // 5 block.Encrypt(next, s[64:80]) xor.BytesSrc1(d[64:80], s[64:80], tbl) // 6 block.Encrypt(tbl, s[80:96]) xor.BytesSrc1(d[80:96], s[80:96], next) // 7 block.Encrypt(next, s[96:112]) xor.BytesSrc1(d[96:112], s[96:112], tbl) // 8 block.Encrypt(tbl, s[112:128]) xor.BytesSrc1(d[112:128], s[112:128], next) base += 128 } switch left { case 7: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 6: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 5: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 4: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 3: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 2: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 1: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += 16 fallthrough case 0: xor.BytesSrc0(dst[base:], src[base:], tbl) } } func decryptVariant(block cipher.Block, dst, src, buf []byte) { blocksize := block.BlockSize() tbl := buf[:blocksize] next := buf[blocksize:] block.Encrypt(tbl, initialVector) n := len(src) / blocksize base := 0 repeat := n / 8 left := n % 8 for i := 0; i < repeat; i++ { // 1 block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) base += blocksize // 2 block.Encrypt(tbl, src[base:]) xor.BytesSrc1(dst[base:], src[base:], next) base += blocksize // 3 block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) base += blocksize // 4 block.Encrypt(tbl, src[base:]) xor.BytesSrc1(dst[base:], src[base:], next) base += blocksize // 5 block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) base += blocksize // 6 block.Encrypt(tbl, src[base:]) xor.BytesSrc1(dst[base:], src[base:], next) base += blocksize // 7 block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) base += blocksize // 8 block.Encrypt(tbl, src[base:]) xor.BytesSrc1(dst[base:], src[base:], next) base += blocksize } switch left { case 7: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += blocksize fallthrough case 6: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += blocksize fallthrough case 5: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += blocksize fallthrough case 4: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += blocksize fallthrough case 3: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += blocksize fallthrough case 2: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += blocksize fallthrough case 1: block.Encrypt(next, src[base:]) xor.BytesSrc1(dst[base:], src[base:], tbl) tbl, next = next, tbl base += blocksize fallthrough case 0: xor.BytesSrc0(dst[base:], src[base:], tbl) } } kcp-go-5.4.4/crypt_test.go000066400000000000000000000114431352301322400154310ustar00rootroot00000000000000package 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.4.4/donate.png000066400000000000000000000105041352301322400146570ustar00rootroot00000000000000PNG  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.4.4/entropy.go000066400000000000000000000017531352301322400147340ustar00rootroot00000000000000package 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.4.4/examples/000077500000000000000000000000001352301322400145155ustar00rootroot00000000000000kcp-go-5.4.4/examples/echo.go000066400000000000000000000030041352301322400157570ustar00rootroot00000000000000package main import ( "crypto/sha1" "io" "log" "time" "github.com/xtaci/kcp-go" "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.4.4/fec.go000066400000000000000000000173411352301322400137710ustar00rootroot00000000000000package kcp import ( "encoding/binary" "sync/atomic" "github.com/klauspost/reedsolomon" ) const ( fecHeaderSize = 6 fecHeaderSizePlus2 = fecHeaderSize + 2 // plus 2B data size typeData = 0xf1 typeParity = 0xf2 ) // 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:] } // fecDecoder for decoding incoming packets type fecDecoder struct { rxlimit int // queue size limit dataShards int parityShards int shardSize int rx []fecPacket // ordered receive queue // caches decodeCache [][]byte flagCache []bool // zeros zeros []byte // RS decoder codec reedsolomon.Encoder } func newFECDecoder(rxlimit, dataShards, parityShards int) *fecDecoder { if dataShards <= 0 || parityShards <= 0 { return nil } if rxlimit < dataShards+parityShards { return nil } dec := new(fecDecoder) dec.rxlimit = rxlimit dec.dataShards = dataShards dec.parityShards = parityShards dec.shardSize = dataShards + parityShards 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) { // 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) // insert into ordered rx queue if insertIdx == n+1 { dec.rx = append(dec.rx, pkt) } else { dec.rx = append(dec.rx, fecPacket{}) copy(dec.rx[insertIdx+1:], dec.rx[insertIdx:]) // shift right dec.rx[insertIdx] = pkt } // 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 { 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) } return } // free a range of fecPacket func (dec *fecDecoder) freeRange(first, n int, q []fecPacket) []fecPacket { for i := first; i < first+n; i++ { // recycle buffer xmitBuf.Put([]byte(q[i])) } if first == 0 && n < cap(q)/2 { return q[n:] } copy(q[first:], q[first+n:]) return q[:len(q)-n] } 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.4.4/fec_test.go000066400000000000000000000016351352301322400150270ustar00rootroot00000000000000package kcp import ( "encoding/binary" "math/rand" "testing" ) func BenchmarkFECDecode(b *testing.B) { const dataSize = 10 const paritySize = 3 const payLoad = 1500 decoder := newFECDecoder(1024, 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.4.4/flame.png000066400000000000000000001574661352301322400145140ustar00rootroot00000000000000PNG  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.4.4/frame.png000066400000000000000000001062461352301322400145100ustar00rootroot00000000000000PNG  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.4.4/kcp-go.png000066400000000000000000000217011352301322400145660ustar00rootroot00000000000000PNG  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) { 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) } } // 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 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) } kcp.parse_una(una) 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 { kcp.cwnd++ } } if kcp.cwnd > kcp.rmt_wnd { kcp.cwnd = kcp.rmt_wnd kcp.incr = kcp.rmt_wnd * mss } } } } 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 ack.sn >= kcp.rcv_nxt || 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, lost, 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 _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.resendts = current + segment.rto lost++ lostSegs++ } 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++ } 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 lost > 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:] } kcp-go-5.4.4/kcp_test.go000066400000000000000000000056701352301322400150520ustar00rootroot00000000000000package 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.Now().Sub(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.4.4/readloop.go000066400000000000000000000017211352301322400150340ustar00rootroot00000000000000package 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 } if n >= s.headerSize+IKCP_OVERHEAD { s.packetInput(buf[:n]) } else { atomic.AddUint64(&DefaultSnmp.InErrs, 1) } } 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 { if n >= l.headerSize+IKCP_OVERHEAD { l.packetInput(buf[:n], from) } else { atomic.AddUint64(&DefaultSnmp.InErrs, 1) } } else { l.notifyReadError(errors.WithStack(err)) return } } } kcp-go-5.4.4/readloop_generic.go000066400000000000000000000002161352301322400165260ustar00rootroot00000000000000// +build !linux package kcp func (s *UDPSession) readLoop() { s.defaultReadLoop() } func (l *Listener) monitor() { l.defaultMonitor() } kcp-go-5.4.4/readloop_linux.go000066400000000000000000000052071352301322400162560ustar00rootroot00000000000000// +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 } if msg.N < s.headerSize+IKCP_OVERHEAD { 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] if msg.N >= l.headerSize+IKCP_OVERHEAD { l.packetInput(msg.Buffers[0][:msg.N], msg.Addr) } else { atomic.AddUint64(&DefaultSnmp.InErrs, 1) } } } 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.4.4/sess.go000066400000000000000000000647311352301322400142160ustar00rootroot00000000000000// 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 // FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory rxFECMulti = 3 // 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 xmitBuf sync.Pool ) func init() { xmitBuf.New = func() interface{} { return make([]byte, mtuLimit) } } type ( // UDPSession defines a KCP session implemented by UDP UDPSession struct { updaterIdx int // record slice index in updater conn net.PacketConn // the underlying packet connection 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, 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.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(rxFECMulti*(dataShards+parityShards), 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) // register current session to the global updater, // which call sess.update() periodically. updater.addSession(sess) if sess.l == nil { // it's a client connection go sess.readLoop() atomic.AddUint64(&DefaultSnmp.ActiveOpens, 1) } else { atomic.AddUint64(&DefaultSnmp.PassiveOpens, 1) } 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 sufficent 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 := s.rd.Sub(time.Now()) 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() if s.kcp.WaitSnd() < int(s.kcp.snd_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:] } } } if s.kcp.WaitSnd() >= int(s.kcp.snd_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 := s.wd.Sub(time.Now()) 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) s.txqueue = s.txqueue[:0] } return } // Close closes the connection. func (s *UDPSession) Close() error { var once bool s.dieOnce.Do(func() { close(s.die) once = true }) if once { // remove from updater updater.removeSession(s) atomic.AddUint64(&DefaultSnmp.CurrEstab, ^uint64(0)) if s.l != nil { // belongs to listener s.l.closeSession(s.remote) return nil } else { // client socket close return s.conn.Close() } } 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) } } // kcp update, returns interval for next calling func (s *UDPSession) update() (interval time.Duration) { s.mu.Lock() waitsnd := s.kcp.WaitSnd() interval = time.Duration(s.kcp.flush(false)) * time.Millisecond if s.kcp.WaitSnd() < waitsnd { s.notifyWriteEvent() } s.uncork() s.mu.Unlock() return } // GetConv gets conversation id of a session func (s *UDPSession) GetConv() uint32 { return s.kcp.conv } 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) { dataValid := false if s.block != nil { s.block.Decrypt(data, data) data = data[nonceSize:] checksum := crc32.ChecksumIEEE(data[crcSize:]) if checksum == binary.LittleEndian.Uint32(data) { data = data[crcSize:] dataValid = true } else { atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1) } } else if s.block == nil { dataValid = true } if dataValid { s.kcpInput(data) } } func (s *UDPSession) kcpInput(data []byte) { var kcpInErrors, fecErrs, fecRecovered, fecParityShards uint64 if s.fecDecoder != nil { if len(data) > fecHeaderSize { // must be larger than fec header size f := fecPacket(data) if f.flag() == typeData || f.flag() == typeParity { // header check if f.flag() == typeParity { fecParityShards++ } recovers := s.fecDecoder.decode(f) s.mu.Lock() waitsnd := s.kcp.WaitSnd() 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 when queue is shorter(e.g. ACKed) if s.kcp.WaitSnd() < waitsnd { s.notifyWriteEvent() } s.uncork() s.mu.Unlock() } else { atomic.AddUint64(&DefaultSnmp.InErrs, 1) } } else { atomic.AddUint64(&DefaultSnmp.InErrs, 1) } } else { s.mu.Lock() waitsnd := s.kcp.WaitSnd() if ret := s.kcp.Input(data, true, s.ackNoDelay); ret != 0 { kcpInErrors++ } if n := s.kcp.PeekSize(); n > 0 { s.notifyReadEvent() } if s.kcp.WaitSnd() < waitsnd { 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 fecDecoder *fecDecoder // FEC mock initialization conn net.PacketConn // the underlying packet connection sessions map[string]*UDPSession // all sessions accepted by this Listener sessionLock sync.Mutex chAccepts chan *UDPSession // Listen() backlog chSessionClosed chan net.Addr // session close queue headerSize int // the additional header to a KCP frame 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) { dataValid := false if l.block != nil { l.block.Decrypt(data, data) data = data[nonceSize:] checksum := crc32.ChecksumIEEE(data[crcSize:]) if checksum == binary.LittleEndian.Uint32(data) { data = data[crcSize:] dataValid = true } else { atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1) } } else if l.block == nil { dataValid = true } if dataValid { l.sessionLock.Lock() s, ok := l.sessions[addr.String()] l.sessionLock.Unlock() if !ok { // new address:port if len(l.chAccepts) < cap(l.chAccepts) { // do not let the new sessions overwhelm accept queue var conv uint32 convValid := false if l.fecDecoder != nil { isfec := binary.LittleEndian.Uint16(data[4:]) if isfec == typeData { conv = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2:]) convValid = true } } else { conv = binary.LittleEndian.Uint32(data) convValid = true } if convValid { // creates a new session only if the 'conv' field in kcp is accessible s := newUDPSession(conv, l.dataShards, l.parityShards, l, l.conn, addr, l.block) s.kcpInput(data) l.sessionLock.Lock() l.sessions[addr.String()] = s l.sessionLock.Unlock() l.chAccepts <- s } } } else { s.kcpInput(data) } } } 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.Lock() for _, s := range l.sessions { s.notifyReadError(err) } l.sessionLock.Unlock() }) } // 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(tdeadline.Sub(time.Now())) } 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 }) if once { return l.conn.Close() } else { return errors.WithStack(io.ErrClosedPipe) } } // 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' specifiy 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) } // ServeConn serves KCP protocol for a single packet connection. func ServeConn(block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*Listener, error) { l := new(Listener) l.conn = conn 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.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards) l.chSocketReadError = make(chan struct{}) // calculate header size if l.block != nil { l.headerSize += cryptHeaderSize } if l.fecDecoder != nil { l.headerSize += fecHeaderSizePlus2 } 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' specifiy 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) } return NewConn(raddr, block, dataShards, parityShards, conn) } // 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, 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.4.4/sess_test.go000066400000000000000000000260151352301322400152460ustar00rootroot00000000000000package 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, 3) } 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() } } kcp-go-5.4.4/snmp.go000066400000000000000000000122701352301322400142050ustar00rootroot00000000000000package 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 infered 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.4.4/tx.go000066400000000000000000000010251352301322400136570ustar00rootroot00000000000000package 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++ xmitBuf.Put(txqueue[k].Buffers[0]) } else { s.notifyWriteError(errors.WithStack(err)) break } } atomic.AddUint64(&DefaultSnmp.OutPkts, uint64(npkts)) atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes)) } kcp-go-5.4.4/tx_generic.go000066400000000000000000000002161352301322400153540ustar00rootroot00000000000000// +build !linux package kcp import ( "golang.org/x/net/ipv4" ) func (s *UDPSession) tx(txqueue []ipv4.Message) { s.defaultTx(txqueue) } kcp-go-5.4.4/tx_linux.go000066400000000000000000000021351352301322400151010ustar00rootroot00000000000000// +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]) xmitBuf.Put(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.4.4/updater.go000066400000000000000000000036241352301322400146770ustar00rootroot00000000000000package kcp import ( "container/heap" "sync" "time" ) var updater updateHeap func init() { updater.init() go updater.updateTask() } // entry contains a session update info type entry struct { ts time.Time s *UDPSession } // a global heap managed kcp.flush() caller type updateHeap struct { entries []entry mu sync.Mutex chWakeUp chan struct{} } func (h *updateHeap) Len() int { return len(h.entries) } func (h *updateHeap) Less(i, j int) bool { return h.entries[i].ts.Before(h.entries[j].ts) } func (h *updateHeap) Swap(i, j int) { h.entries[i], h.entries[j] = h.entries[j], h.entries[i] h.entries[i].s.updaterIdx = i h.entries[j].s.updaterIdx = j } func (h *updateHeap) Push(x interface{}) { h.entries = append(h.entries, x.(entry)) n := len(h.entries) h.entries[n-1].s.updaterIdx = n - 1 } func (h *updateHeap) Pop() interface{} { n := len(h.entries) x := h.entries[n-1] h.entries[n-1].s.updaterIdx = -1 h.entries[n-1] = entry{} // manual set nil for GC h.entries = h.entries[0 : n-1] return x } func (h *updateHeap) init() { h.chWakeUp = make(chan struct{}, 1) } func (h *updateHeap) addSession(s *UDPSession) { h.mu.Lock() heap.Push(h, entry{time.Now(), s}) h.mu.Unlock() h.wakeup() } func (h *updateHeap) removeSession(s *UDPSession) { h.mu.Lock() if s.updaterIdx != -1 { heap.Remove(h, s.updaterIdx) } h.mu.Unlock() } func (h *updateHeap) wakeup() { select { case h.chWakeUp <- struct{}{}: default: } } func (h *updateHeap) updateTask() { timer := time.NewTimer(0) for { select { case <-timer.C: case <-h.chWakeUp: } h.mu.Lock() hlen := h.Len() for i := 0; i < hlen; i++ { entry := &h.entries[0] if !time.Now().Before(entry.ts) { interval := entry.s.update() entry.ts = time.Now().Add(interval) heap.Fix(h, 0) } else { break } } if hlen > 0 { timer.Reset(h.entries[0].ts.Sub(time.Now())) } h.mu.Unlock() } }