-
Notifications
You must be signed in to change notification settings - Fork 731
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4976678
Showing
15 changed files
with
3,038 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
language: go | ||
go: | ||
- 1.6 | ||
before_install: | ||
- go get github.com/mattn/goveralls | ||
- go get golang.org/x/tools/cmd/cover | ||
install: | ||
- go get github.com/xtaci/kcp-go | ||
before_script: | ||
script: | ||
- $HOME/gopath/bin/goveralls -service=travis-ci | ||
- exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
The 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. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# ***kcp-go*** :pisces: | ||
[![GoDoc][1]][2] [![Powered][9]][10] [![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://coveralls.io/repos/github/xtaci/kcp-go/badge.svg?branch=master | ||
[8]: https://coveralls.io/github/xtaci/kcp-go?branch=master | ||
[9]: https://img.shields.io/badge/KCP-Powered-blue.svg | ||
[10]: https://github.com/skywind3000/kcp | ||
|
||
***A full-featured reliable UDP communication library for various usage*** | ||
|
||
# ***Features*** :zap: | ||
1. Optimized for ***game development***. | ||
1. Compatible with [skywind3000's](https://github.com/skywind3000) C version with modificiations. | ||
1. ***Cache friendly*** and ***Memory optimized*** design in golang. | ||
1. A [session manager](https://github.com/xtaci/kcp-go/blob/master/sess.go) has provided with compatiablity for [net.Conn](https://golang.org/pkg/net/#Conn) and [net.Listener](https://golang.org/pkg/net/#Listener). | ||
1. Support [FEC(Forward Error Correction)](https://en.wikipedia.org/wiki/Forward_error_correction) with [Reed-Solomon Codes](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction) | ||
1. Support packet level encryption with [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard), [TEA](https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm). | ||
|
||
# ***Conventions*** :zap: | ||
1. [UDP](https://en.wikipedia.org/wiki/User_Datagram_Protocol) for packet delivery. | ||
2. ```conv uint32``` in session manager is a ***random number*** initiated by client. | ||
3. KCP doesn't define control messages like SYN/ACK/FIN/RST in TCP, a real world example is to use some ***multiplexing*** protocol over session, such as [yamux](https://github.com/hashicorp/yamux), see [kcptun](https://github.com/xtaci/kcptun) for example. | ||
|
||
# ***Examples*** :zap: | ||
Client: [full demo](https://github.com/xtaci/kcptun/blob/master/client/main.go#L231) | ||
```go | ||
kcpconn, err := kcp.DialWithOptions("192.168.0.1:10000", nil, 10, 3) | ||
``` | ||
Server: [full demo](https://github.com/xtaci/kcptun/blob/master/server/main.go#L235) | ||
```go | ||
lis, err := kcp.ListenWithOptions(":10000", nil, 10, 3) | ||
``` | ||
|
||
# ***Performance*** :zap: | ||
``` | ||
型号名称: MacBook Pro | ||
型号标识符: MacBookPro12,1 | ||
处理器名称: Intel Core i5 | ||
处理器速度: 2.7 GHz | ||
处理器数目: 1 | ||
核总数: 2 | ||
L2 缓存(每个核): 256 KB | ||
L3 缓存: 3 MB | ||
内存: 8 GB | ||
``` | ||
``` | ||
$ go test -run Speed | ||
new client 127.0.0.1:61165 | ||
total recv: 16777216 | ||
time for 16MB rtt with encryption 570.41176ms | ||
&{BytesSent:33554432 BytesReceived:33554432 MaxConn:2 ActiveOpens:1 PassiveOpens:1 CurrEstab:1 InErrs:0 InCsumErrors:0 InSegs:42577 OutSegs:42641 OutBytes:48111336 RetransSegs:92 FastRetransSegs:92 LostSegs:0 RepeatSegs:0 FECRecovered:1 FECErrs:0 FECSegs:8514} | ||
PASS | ||
ok github.com/xtaci/kcp-go 0.600s | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package kcp | ||
|
||
import ( | ||
"crypto/aes" | ||
"crypto/cipher" | ||
"crypto/sha1" | ||
|
||
"golang.org/x/crypto/pbkdf2" | ||
"golang.org/x/crypto/tea" | ||
) | ||
|
||
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 | ||
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) | ||
} | ||
|
||
// AESBlockCrypt implements BlockCrypt with AES | ||
type AESBlockCrypt struct { | ||
encbuf []byte | ||
decbuf []byte | ||
block cipher.Block | ||
} | ||
|
||
// NewAESBlockCrypt initates AES BlockCrypt by the given key | ||
func NewAESBlockCrypt(key []byte) (BlockCrypt, error) { | ||
c := new(AESBlockCrypt) | ||
block, err := aes.NewCipher(key) | ||
if err != nil { | ||
return nil, err | ||
} | ||
c.block = block | ||
c.encbuf = make([]byte, aes.BlockSize) | ||
c.decbuf = make([]byte, 2*aes.BlockSize) | ||
return c, nil | ||
} | ||
|
||
// Encrypt implements Encrypt interface | ||
func (c *AESBlockCrypt) Encrypt(dst, src []byte) { | ||
encrypt(c.block, dst, src, c.encbuf) | ||
} | ||
|
||
// Decrypt implements Decrypt interface | ||
func (c *AESBlockCrypt) Decrypt(dst, src []byte) { | ||
decrypt(c.block, dst, src, c.decbuf) | ||
} | ||
|
||
// TEABlockCrypt implements BlockCrypt with TEA | ||
type TEABlockCrypt struct { | ||
encbuf []byte | ||
decbuf []byte | ||
block cipher.Block | ||
} | ||
|
||
// NewTEABlockCrypt initate TEA BlockCrypt by the given key | ||
func NewTEABlockCrypt(key []byte) (BlockCrypt, error) { | ||
c := new(TEABlockCrypt) | ||
block, err := tea.NewCipherWithRounds(key, 16) | ||
if err != nil { | ||
return nil, err | ||
} | ||
c.block = block | ||
c.encbuf = make([]byte, tea.BlockSize) | ||
c.decbuf = make([]byte, 2*tea.BlockSize) | ||
return c, nil | ||
} | ||
|
||
// Encrypt implements Encrypt interface | ||
func (c *TEABlockCrypt) Encrypt(dst, src []byte) { | ||
encrypt(c.block, dst, src, c.encbuf) | ||
} | ||
|
||
// Decrypt implements Decrypt interface | ||
func (c *TEABlockCrypt) Decrypt(dst, src []byte) { | ||
decrypt(c.block, dst, src, c.decbuf) | ||
} | ||
|
||
// SimpleXORBlockCrypt implements BlockCrypt with simple xor to a table | ||
type SimpleXORBlockCrypt struct { | ||
xortbl []byte | ||
} | ||
|
||
// NewSimpleXORBlockCrypt initate SimpleXORBlockCrypt by the given key | ||
func NewSimpleXORBlockCrypt(key []byte) (BlockCrypt, error) { | ||
c := new(SimpleXORBlockCrypt) | ||
c.xortbl = pbkdf2.Key(key, []byte(saltxor), 32, mtuLimit, sha1.New) | ||
return c, nil | ||
} | ||
|
||
// Encrypt implements Encrypt interface | ||
func (c *SimpleXORBlockCrypt) Encrypt(dst, src []byte) { | ||
xorBytes(dst, src, c.xortbl) | ||
} | ||
|
||
// Decrypt implements Decrypt interface | ||
func (c *SimpleXORBlockCrypt) Decrypt(dst, src []byte) { | ||
xorBytes(dst, src, c.xortbl) | ||
} | ||
|
||
// NoneBlockCrypt simple returns the plaintext | ||
type NoneBlockCrypt struct { | ||
xortbl []byte | ||
} | ||
|
||
// NewNoneBlockCrypt initate NoneBlockCrypt by the given key | ||
func NewNoneBlockCrypt(key []byte) (BlockCrypt, error) { | ||
return new(NoneBlockCrypt), nil | ||
} | ||
|
||
// Encrypt implements Encrypt interface | ||
func (c *NoneBlockCrypt) Encrypt(dst, src []byte) {} | ||
|
||
// Decrypt implements Decrypt interface | ||
func (c *NoneBlockCrypt) Decrypt(dst, src []byte) {} | ||
|
||
// packet encryption with local CFB mode | ||
func encrypt(block cipher.Block, dst, src, buf []byte) { | ||
blocksize := block.BlockSize() | ||
tbl := buf[:blocksize] | ||
block.Encrypt(tbl, initialVector) | ||
n := len(src) / blocksize | ||
base := 0 | ||
for i := 0; i < n; i++ { | ||
xorWords(dst[base:], src[base:], tbl) | ||
block.Encrypt(tbl, dst[base:]) | ||
base += blocksize | ||
} | ||
xorBytes(dst[base:], src[base:], tbl) | ||
} | ||
|
||
func decrypt(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 | ||
for i := 0; i < n; i++ { | ||
block.Encrypt(next, src[base:]) | ||
xorWords(dst[base:], src[base:], tbl) | ||
tbl, next = next, tbl | ||
base += blocksize | ||
} | ||
xorBytes(dst[base:], src[base:], tbl) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package kcp | ||
|
||
import ( | ||
"crypto/sha1" | ||
"testing" | ||
|
||
"golang.org/x/crypto/pbkdf2" | ||
) | ||
|
||
const crypt_key = "testkey" | ||
const crypt_salt = "kcptest" | ||
|
||
func TestAES(t *testing.T) { | ||
pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New) | ||
bc, err := NewAESBlockCrypt(pass) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
data := make([]byte, 4096) | ||
for i := 0; i < 4096; i++ { | ||
data[i] = byte(i & 0xff) | ||
} | ||
bc.Encrypt(data, data) | ||
bc.Decrypt(data, data) | ||
t.Log(data) | ||
} | ||
|
||
func TestTEA(t *testing.T) { | ||
pass := pbkdf2.Key(key, []byte(salt), 4096, 16, sha1.New) | ||
bc, err := NewTEABlockCrypt(pass) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
data := make([]byte, 4096) | ||
for i := 0; i < 4096; i++ { | ||
data[i] = byte(i & 0xff) | ||
} | ||
bc.Encrypt(data, data) | ||
bc.Decrypt(data, data) | ||
t.Log(data) | ||
} | ||
|
||
func TestSimpleXOR(t *testing.T) { | ||
pass := pbkdf2.Key(key, []byte(salt), 4096, 16, sha1.New) | ||
bc, err := NewSimpleXORBlockCrypt(pass) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
data := make([]byte, 4096) | ||
for i := 0; i < 4096; i++ { | ||
data[i] = byte(i & 0xff) | ||
} | ||
bc.Encrypt(data, data) | ||
bc.Decrypt(data, data) | ||
t.Log(data) | ||
} |
Oops, something went wrong.