Merge pull request #44 from aliiohs/feature/addTlsSupport
Feature/add tls support
diff --git a/client.go b/client.go
index e61bf8a..394c27c 100644
--- a/client.go
+++ b/client.go
@@ -125,7 +125,7 @@
c := newClient(WSS_CLIENT, opts...)
if c.cert == "" {
- panic(fmt.Sprintf("@cert:%s", c.cert))
+ panic(fmt.Sprintf("@certs:%s", c.cert))
}
if !strings.HasPrefix(c.addr, "wss://") {
panic(fmt.Sprintf("the prefix @serverAddr:%s is not wss://", c.addr))
@@ -152,7 +152,14 @@
if c.IsClosed() {
return nil
}
- conn, err = net.DialTimeout("tcp", c.addr, connectTimeout)
+ if c.sslEnabled {
+ if sslConfig, err := c.tlsConfigBuilder.BuildTlsConfig(); err == nil && sslConfig != nil {
+ d := &net.Dialer{Timeout: connectTimeout}
+ conn, err = tls.DialWithDialer(d, "tcp", c.addr, sslConfig)
+ }
+ } else {
+ conn, err = net.DialTimeout("tcp", c.addr, connectTimeout)
+ }
if err == nil && gxnet.IsSameAddr(conn.RemoteAddr(), conn.LocalAddr()) {
conn.Close()
err = errSelfConnect
@@ -277,7 +284,7 @@
if c.cert != "" {
certPEMBlock, err := ioutil.ReadFile(c.cert)
if err != nil {
- panic(fmt.Sprintf("ioutil.ReadFile(cert:%s) = error:%+v", c.cert, perrors.WithStack(err)))
+ panic(fmt.Sprintf("ioutil.ReadFile(certs:%s) = error:%+v", c.cert, perrors.WithStack(err)))
}
var cert tls.Certificate
@@ -299,7 +306,7 @@
for _, c := range config.Certificates {
roots, err = x509.ParseCertificates(c.Certificate[len(c.Certificate)-1])
if err != nil {
- panic(fmt.Sprintf("error parsing server's root cert: %+v\n", perrors.WithStack(err)))
+ panic(fmt.Sprintf("error parsing server's root certs: %+v\n", perrors.WithStack(err)))
}
for _, root = range roots {
certPool.AddCert(root)
diff --git a/connection.go b/connection.go
index 878aa56..458b6c0 100644
--- a/connection.go
+++ b/connection.go
@@ -37,7 +37,7 @@
var (
launchTime = time.Now()
-// ErrInvalidConnection = perrors.New("connection has been closed.")
+ // ErrInvalidConnection = perrors.New("connection has been closed.")
)
/////////////////////////////////////////
@@ -322,8 +322,13 @@
log.Errorf("snappy.Writer.Close() = error:%+v", err)
}
}
- t.conn.(*net.TCPConn).SetLinger(waitSec)
- t.conn.Close()
+ if conn, ok := t.conn.(*net.TCPConn); ok {
+ _ = conn.SetLinger(waitSec)
+ _ = conn.Close()
+ } else {
+ _ = t.conn.(*tls.Conn).Close()
+
+ }
t.conn = nil
}
}
diff --git a/demo/hello/tls/certs/ca.key b/demo/hello/tls/certs/ca.key
new file mode 100644
index 0000000..03c4f95
--- /dev/null
+++ b/demo/hello/tls/certs/ca.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMBA3wVeTGHZR1Ry
+e/i+J8a2cu5gXwFV6TnObzGM7bLFCO5i9v4mLo4iFzPsHmWDUxKS3Y8iXbu0eYBl
+LoNY0lSvxDx33O+DuwMmVN+DzSD+Eod9zfvwOWHsazYCZT2PhNxnVWIuJXViY4JA
+HUGodjx+QAi6yCAurUZGvYXGgZSBAgMBAAECgYAxRi8i9BlFlufGSBVoGmydbJOm
+bwLKl9dP3o33ODSP9hok5y6A0w5plWk3AJSF1hPLleK9VcSKYGYnt0clmPVHF35g
+bx2rVK8dOT0mn7rz9Zr70jcSz1ETA2QonHZ+Y+niLmcic9At6hRtWiewblUmyFQm
+GwggIzi7LOyEUHrEcQJBAOXxyQvnLvtKzXiqcsW/K6rExqVJVk+KF0fzzVyMzTJx
+HRBxUVgvGdEJT7j+7P2kcTyafve0BBzDSPIaDyiJ+Y0CQQDWCb7jASFSbu5M3Zcd
+Gkr4ZKN1XO3VLQX10b22bQYdF45hrTN2tnzRvVUR4q86VVnXmiGiTqmLkXcA2WWf
+pHfFAkAhv9olUBo6MeF0i3frBEMRfm41hk0PwZHnMqZ6pgPcGnQMnMU2rzsXzkkQ
+OwJnvAIOxhJKovZTjmofdqmw5odlAkBYVUdRWjsNUTjJwj3GRf6gyq/nFMYWz3EB
+RWFdM1ttkDYzu45ctO2IhfHg4sPceDMO1s6AtKQmNI9/azkUjITdAkApNa9yFRzc
+TBaDNPd5KVd58LVIzoPQ6i7uMHteLXJUWqSroji6S3s4gKMFJ/dO+ZXIlgQgfJJJ
+ZDL4cdrdkeoM
+-----END PRIVATE KEY-----
diff --git a/demo/hello/tls/certs/ca.pem b/demo/hello/tls/certs/ca.pem
new file mode 100644
index 0000000..6c8511a
--- /dev/null
+++ b/demo/hello/tls/certs/ca.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
+Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
+YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
+BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
+g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
+Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
+sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
+oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
+Dfcog5wrJytaQ6UA0wE=
+-----END CERTIFICATE-----
diff --git a/demo/hello/tls/certs/client.key b/demo/hello/tls/certs/client.key
new file mode 100644
index 0000000..f48d073
--- /dev/null
+++ b/demo/hello/tls/certs/client.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM
+s5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM
+JCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT
+NKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS
+k2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH
+0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS
+W2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI
+w2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5
+0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5
+/sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/
+U0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP
+1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd
+9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI
+JiqOszq9GWESErAatg==
+-----END PRIVATE KEY-----
diff --git a/demo/hello/tls/certs/client.pem b/demo/hello/tls/certs/client.pem
new file mode 100644
index 0000000..913649b
--- /dev/null
+++ b/demo/hello/tls/certs/client.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6TCCAlKgAwIBAgIBCjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTEwMDEwOTU4WhcNMjUxMTA3
+MDEwOTU4WjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8G
+A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYDVQQDDAp0ZXN0Y2xp
+ZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsVEfbob4W3lVCDLOVmx9K
+cdJnoZdvurGaTY87xNiopmaR8zCR7pFR9BX5L4bNG/PkuVLfVTVAKndyDCQggBBr
+UTaEITNbfWK9swHJEr20WnKfhS/wo/Xg5sqNNCrFRmnnnwOA4eDlvmYZEzSnJXV6
+pEro9bBH9uOCWWLqmaev7QIDAQABo4HCMIG/MAkGA1UdEwQCMAAwCwYDVR0PBAQD
+AgXgMB0GA1UdDgQWBBQAdbW5Vml/CnYwqdP3mOHDARU+8zBwBgNVHSMEaTBnoVqk
+WDBWMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMY
+SW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2GCCQCRxhke
+HRoqBzAJBgNVHREEAjAAMAkGA1UdEgQCMAAwDQYJKoZIhvcNAQELBQADgYEAf4MM
+k+sdzd720DfrQ0PF2gDauR3M9uBubozDuMuF6ufAuQBJSKGQEGibXbUelrwHmnql
+UjTyfolVcxEBVaF4VFHmn7u6vP7S1NexIDdNUHcULqxIb7Tzl8JYq8OOHD2rQy4H
+s8BXaVIzw4YcaCGAMS0iDX052Sy7e2JhP8Noxvo=
+-----END CERTIFICATE-----
diff --git a/demo/hello/tls/certs/server0.key b/demo/hello/tls/certs/server0.key
new file mode 100644
index 0000000..add153c
--- /dev/null
+++ b/demo/hello/tls/certs/server0.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANOmffupIGC8YDau
+rOF4eKnHwPszgpkkhWzKsVxhNDBxCVYx4TEjG0XWIO0iyRXupZbUC+7N/8HnEVNa
+8F1jYhng14Iiq99cNQbbnuHHhIztmpocrJTxmnhGzoAnRa1Tb+GnAuRoIHRA/V2c
+VUE9tbikQugFx/SPgXAw6tfWB+YvAgMBAAECgYEAoEq9qzUBgoHoVEGiSPiWWe8g
+5p6yUA1qx2QTQyWTAwT4z0DjjfVKmG99bFsl8+hTnJFnoCp/gnjflEOROwkjp5kG
+m0drqOPx1jeipJjpXYTBu49h+WpZ1PF+KhVtxsIm3OOCvh67iWaKyyOVb5Og8aiR
+jl6dn/TdG/dlGD8AfUECQQDuNMle6p0oU8amC6O9wIMBroxx2nFstzE6O35PLEzG
+/tj0kxxn9Jp2TS9mGaLCzSuXmpjlF4+NOWiBPkrLC2TfAkEA43Xg7uEUkaJAz2/W
+m1lIBTLt+4rIQY/2emh33bDcA+rv8rwwrMMIv17/xPx7bs49YqGG5xufD+Rwl6TL
+qFXYsQJAPrOwagax1aKvwJeBw3oAQhoTKAkLIEXcdGqipe6QSzVcIIz0xjxxyEAr
+AOIwoLxnBCISqwMXq2H4K0UdZPMb2wJAdhdYLY1L6YRMk6XjzImg25oidisKZweA
+FvMv8DgHMj2CUAqmVrt3SivfLH1M9C09L3zfFhOAFHcsgX58gav4MQJBANSBnrHj
+tIq4l8z79CPUIuu3QyeEh+XwY8s5qE5CNTck0U59lzp9NvENHbkx3KO896TTerko
++8bXHMLkJkHPXms=
+-----END PRIVATE KEY-----
diff --git a/demo/hello/tls/certs/server0.pem b/demo/hello/tls/certs/server0.pem
new file mode 100644
index 0000000..9458954
--- /dev/null
+++ b/demo/hello/tls/certs/server0.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8zCCAlygAwIBAgIBCzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTEwMDExNDU1WhcNMjUxMTA3
+MDExNDU1WjBkMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8G
+A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMR0wGwYDVQQDDBQqLnRlc3Qu
+Z29vZ2xlLmNvbS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA06Z9+6kg
+YLxgNq6s4Xh4qcfA+zOCmSSFbMqxXGE0MHEJVjHhMSMbRdYg7SLJFe6lltQL7s3/
+wecRU1rwXWNiGeDXgiKr31w1Btue4ceEjO2amhyslPGaeEbOgCdFrVNv4acC5Ggg
+dED9XZxVQT21uKRC6AXH9I+BcDDq19YH5i8CAwEAAaOBwjCBvzAJBgNVHRMEAjAA
+MAsGA1UdDwQEAwIF4DAdBgNVHQ4EFgQUbyZIbUvqmePzv40xa0mMaDxLToYwcAYD
+VR0jBGkwZ6FapFgwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx
+ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAxMGdGVz
+dGNhggkAkcYZHh0aKgcwCQYDVR0RBAIwADAJBgNVHRIEAjAAMA0GCSqGSIb3DQEB
+CwUAA4GBAJ21MwMf4WwAjafPKn+8Ng7ordtdp6tlkjt+Xub4l4zMr6FCp6dc/Ceh
+6Hj43zYcKpAe5I6eaVcMc9qcYfUb9i4NVX82dMQpAwpNHgqTzqYt6GYEjF3YhKA7
+uOFdA0OvOFJa14SNdNRk9E1Cd/tElXnLnSE4DOguMNvXz8mRKfnD
+-----END CERTIFICATE-----
diff --git a/demo/hello/tls/client/client.go b/demo/hello/tls/client/client.go
new file mode 100644
index 0000000..ee0b717
--- /dev/null
+++ b/demo/hello/tls/client/client.go
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+ "flag"
+ "path/filepath"
+)
+
+import (
+ "github.com/dubbogo/getty"
+ "github.com/dubbogo/gost/sync"
+)
+
+import (
+ "github.com/dubbogo/getty/demo/hello"
+ tls "github.com/dubbogo/getty/demo/hello/tls"
+ "github.com/dubbogo/getty/demo/util"
+)
+
+var (
+ ip = flag.String("ip", "127.0.0.1", "server IP")
+ connections = flag.Int("conn", 1, "number of tcp connections")
+
+ taskPoolMode = flag.Bool("taskPool", false, "task pool mode")
+ taskPoolQueueLength = flag.Int("task_queue_length", 100, "task queue length")
+ taskPoolQueueNumber = flag.Int("task_queue_number", 4, "task queue number")
+ taskPoolSize = flag.Int("task_pool_size", 2000, "task poll size")
+ pprofPort = flag.Int("pprof_port", 65431, "pprof http port")
+)
+
+var (
+ taskPool *gxsync.TaskPool
+)
+
+func main() {
+ flag.Parse()
+
+ util.SetLimit()
+
+ util.Profiling(*pprofPort)
+
+ if *taskPoolMode {
+ taskPool = gxsync.NewTaskPool(
+ gxsync.WithTaskPoolTaskQueueLength(*taskPoolQueueLength),
+ gxsync.WithTaskPoolTaskQueueNumber(*taskPoolQueueNumber),
+ gxsync.WithTaskPoolTaskPoolSize(*taskPoolSize),
+ )
+ }
+ keyPath, _ := filepath.Abs("./demo/hello/tls/certs/ca.key")
+ caPemPath, _ := filepath.Abs("./demo/hello/tls/certs/ca.pem")
+
+ config := &getty.ClientTlsConfigBuilder{
+ ClientTrustCertCollectionPath: caPemPath,
+ ClientPrivateKeyPath: keyPath,
+ }
+ client := getty.NewTCPClient(
+ getty.WithServerAddress(*ip+":8090"),
+ getty.WithClientSslEnabled(true),
+ getty.WithClientTlsConfigBuilder(config),
+ getty.WithConnectionNumber(*connections),
+ )
+
+ client.RunEventLoop(NewHelloClientSession)
+
+ go hello.ClientRequest()
+
+ util.WaitCloseSignals(client)
+ taskPool.Close()
+}
+
+// NewHelloClientSession use for init client session
+func NewHelloClientSession(session getty.Session) (err error) {
+ tls.EventListener.SessionOnOpen = func(session getty.Session) {
+ hello.Sessions = append(hello.Sessions, session)
+ }
+ err = tls.InitialSession(session)
+ if err != nil {
+ return
+ }
+ return
+}
diff --git a/demo/hello/tls/config.go b/demo/hello/tls/config.go
new file mode 100644
index 0000000..49fa5cf
--- /dev/null
+++ b/demo/hello/tls/config.go
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tcp
+
+import (
+ "crypto/tls"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/getty"
+)
+
+import (
+ "github.com/dubbogo/getty/demo/hello"
+)
+
+var (
+ pkgHandler = &hello.PackageHandler{}
+ // EventListener register event callback
+ EventListener = &hello.MessageHandler{}
+)
+
+func InitialSession(session getty.Session) (err error) {
+ //session.SetCompressType(getty.CompressZip)
+ _, ok := session.Conn().(*tls.Conn)
+ if ok {
+ session.SetName("hello")
+ session.SetMaxMsgLen(128)
+ // session.SetRQLen(1024)
+ session.SetWQLen(512)
+ session.SetReadTimeout(time.Second)
+ session.SetWriteTimeout(5 * time.Second)
+ session.SetCronPeriod(int(hello.CronPeriod / 1e6))
+ session.SetWaitTime(time.Second)
+
+ session.SetPkgHandler(pkgHandler)
+ session.SetEventListener(EventListener)
+ }
+ return nil
+}
diff --git a/demo/hello/tls/server/server.go b/demo/hello/tls/server/server.go
new file mode 100644
index 0000000..3f6ed38
--- /dev/null
+++ b/demo/hello/tls/server/server.go
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+ "flag"
+ tls "github.com/dubbogo/getty/demo/hello/tls"
+ "path/filepath"
+)
+
+import (
+ "github.com/dubbogo/getty"
+ gxsync "github.com/dubbogo/gost/sync"
+)
+
+import (
+ "github.com/dubbogo/getty/demo/util"
+)
+
+var (
+ taskPoolMode = flag.Bool("taskPool", false, "task pool mode")
+ taskPoolQueueLength = flag.Int("task_queue_length", 100, "task queue length")
+ taskPoolQueueNumber = flag.Int("task_queue_number", 4, "task queue number")
+ taskPoolSize = flag.Int("task_pool_size", 2000, "task poll size")
+ pprofPort = flag.Int("pprof_port", 65432, "pprof http port")
+ Sessions []getty.Session
+)
+
+var (
+ taskPool *gxsync.TaskPool
+)
+
+func main() {
+ flag.Parse()
+
+ util.SetLimit()
+
+ util.Profiling(*pprofPort)
+ serverPemPath, _ := filepath.Abs("./demo/hello/tls/certs/server0.pem")
+ serverKeyPath, _ := filepath.Abs("./demo/hello/tls/certs/server0.key")
+ caPemPath, _ := filepath.Abs("./demo/hello/tls/certs/ca.pem")
+
+ c := &getty.ServerTlsConfigBuilder{
+ ServerKeyCertChainPath: serverPemPath,
+ ServerPrivateKeyPath: serverKeyPath,
+ ServerTrustCertCollectionPath: caPemPath,
+ }
+
+ options := []getty.ServerOption{getty.WithLocalAddress(":8090"),
+ getty.WithServerSslEnabled(true),
+ getty.WithServerTlsConfigBuilder(c),
+ }
+
+ if *taskPoolMode {
+ taskPool = gxsync.NewTaskPool(
+ gxsync.WithTaskPoolTaskQueueLength(*taskPoolQueueLength),
+ gxsync.WithTaskPoolTaskQueueNumber(*taskPoolQueueNumber),
+ gxsync.WithTaskPoolTaskPoolSize(*taskPoolSize),
+ )
+ }
+
+ server := getty.NewTCPServer(options...)
+
+ go server.RunEventLoop(NewHelloServerSession)
+ util.WaitCloseSignals(server)
+}
+
+func NewHelloServerSession(session getty.Session) (err error) {
+ err = tls.InitialSession(session)
+ Sessions = append(Sessions, session)
+ if err != nil {
+ return
+ }
+ session.SetTaskPool(taskPool)
+
+ return
+}
diff --git a/go.mod b/go.mod
index cea42bf..ee54516 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,7 @@
module github.com/dubbogo/getty
+go 1.14
+
require (
github.com/dubbogo/gost v1.9.0
github.com/golang/snappy v0.0.1
@@ -8,5 +10,3 @@
github.com/stretchr/testify v1.5.1
go.uber.org/zap v1.15.0
)
-
-go 1.13
diff --git a/options.go b/options.go
index dfbbaa6..a28c240 100644
--- a/options.go
+++ b/options.go
@@ -25,7 +25,9 @@
type ServerOptions struct {
addr string
-
+ //tls
+ sslEnabled bool
+ tlsConfigBuilder TlsConfigBuilder
// websocket
path string
cert string
@@ -47,7 +49,7 @@
}
}
-// @cert: server certificate file
+// @certs: server certificate file
func WithWebsocketServerCert(cert string) ServerOption {
return func(o *ServerOptions) {
o.cert = cert
@@ -61,13 +63,27 @@
}
}
-// @cert is the root certificate file to verify the legitimacy of server
+// @certs is the root certificate file to verify the legitimacy of server
func WithWebsocketServerRootCert(cert string) ServerOption {
return func(o *ServerOptions) {
o.caCert = cert
}
}
+// @WithSslEnabled enable use tls
+func WithServerSslEnabled(sslEnabled bool) ServerOption {
+ return func(o *ServerOptions) {
+ o.sslEnabled = sslEnabled
+ }
+}
+
+// @WithServerKeyCertChainPath sslConfig is tls config
+func WithServerTlsConfigBuilder(tlsConfigBuilder TlsConfigBuilder) ServerOption {
+ return func(o *ServerOptions) {
+ o.tlsConfigBuilder = tlsConfigBuilder
+ }
+}
+
/////////////////////////////////////////
// Client Options
/////////////////////////////////////////
@@ -79,7 +95,11 @@
number int
reconnectInterval int // reConnect Interval
- // the cert file of wss server which may contain server domain, server ip, the starting effective date, effective
+ //tls
+ sslEnabled bool
+ tlsConfigBuilder TlsConfigBuilder
+
+ // the certs file of wss server which may contain server domain, server ip, the starting effective date, effective
// duration, the hash alg, the len of the private key.
// wss client will use it.
cert string
@@ -110,9 +130,23 @@
}
}
-// @cert is client certificate file. it can be empty.
+// @certs is client certificate file. it can be empty.
func WithRootCertificateFile(cert string) ClientOption {
return func(o *ClientOptions) {
o.cert = cert
}
}
+
+// @WithSslEnabled enable use tls
+func WithClientSslEnabled(sslEnabled bool) ClientOption {
+ return func(o *ClientOptions) {
+ o.sslEnabled = sslEnabled
+ }
+}
+
+// @WithClientKeyCertChainPath sslConfig is tls config
+func WithClientTlsConfigBuilder(tlsConfigBuilder TlsConfigBuilder) ClientOption {
+ return func(o *ClientOptions) {
+ o.tlsConfigBuilder = tlsConfigBuilder
+ }
+}
diff --git a/server.go b/server.go
index 82944bd..510f15e 100644
--- a/server.go
+++ b/server.go
@@ -56,7 +56,6 @@
lock sync.Mutex // for server
endPointType EndPointType
server *http.Server // for ws or wss server
-
sync.Once
done chan struct{}
wg sync.WaitGroup
@@ -80,7 +79,7 @@
return s
}
-// NewTCServer builds a tcp server.
+// NewTCPServer builds a tcp server.
func NewTCPServer(opts ...ServerOption) Server {
return newServer(TCP_SERVER, opts...)
}
@@ -100,7 +99,7 @@
s := newServer(WSS_SERVER, opts...)
if s.addr == "" || s.cert == "" || s.privateKey == "" {
- panic(fmt.Sprintf("@addr:%s, @cert:%s, @privateKey:%s, @caCert:%s",
+ panic(fmt.Sprintf("@addr:%s, @certs:%s, @privateKey:%s, @caCert:%s",
s.addr, s.cert, s.privateKey, s.caCert))
}
@@ -175,7 +174,13 @@
return perrors.Wrapf(err, "gxnet.ListenOnTCPRandomPort(addr:%s)", s.addr)
}
} else {
- streamListener, err = net.Listen("tcp", s.addr)
+ if s.sslEnabled {
+ if sslConfig, err := s.tlsConfigBuilder.BuildTlsConfig(); err == nil && sslConfig != nil {
+ streamListener, err = tls.Listen("tcp", s.addr, sslConfig)
+ }
+ } else {
+ streamListener, err = net.Listen("tcp", s.addr)
+ }
if err != nil {
return perrors.Wrapf(err, "net.Listen(tcp, addr:%s)", s.addr)
}
@@ -409,12 +414,12 @@
defer s.wg.Done()
if certificate, err = tls.LoadX509KeyPair(s.cert, s.privateKey); err != nil {
- panic(fmt.Sprintf("tls.LoadX509KeyPair(cert{%s}, privateKey{%s}) = err:%+v",
+ panic(fmt.Sprintf("tls.LoadX509KeyPair(certs{%s}, privateKey{%s}) = err:%+v",
s.cert, s.privateKey, perrors.WithStack(err)))
return
}
config = &tls.Config{
- InsecureSkipVerify: true, // do not verify peer cert
+ InsecureSkipVerify: true, // do not verify peer certs
ClientAuth: tls.NoClientCert,
NextProtos: []string{"http/1.1"},
Certificates: []tls.Certificate{certificate},
diff --git a/server_test.go b/server_test.go
index 01a9270..3c4a10d 100644
--- a/server_test.go
+++ b/server_test.go
@@ -18,6 +18,7 @@
package getty
import (
+ "path/filepath"
"testing"
"time"
)
@@ -75,6 +76,75 @@
server.Close()
assert.True(t, server.IsClosed())
}
+func testTCPTlsServer(t *testing.T, address string) {
+ var (
+ server *server
+ serverMsgHandler MessageHandler
+ )
+ serverPemPath, _ := filepath.Abs("./demo/hello/tls/certs/server0.pem")
+ serverKeyPath, _ := filepath.Abs("./demo/hello/tls/certs/server0.key")
+ caPemPath, _ := filepath.Abs("./demo/hello/tls/certs/ca.pem")
+
+ configBuilder := &ServerTlsConfigBuilder{
+ ServerKeyCertChainPath: serverPemPath,
+ ServerPrivateKeyPath: serverKeyPath,
+ ServerTrustCertCollectionPath: caPemPath,
+ }
+
+ func() {
+ server = newServer(
+ TCP_SERVER,
+ WithLocalAddress(address),
+ WithServerSslEnabled(true),
+ WithServerTlsConfigBuilder(configBuilder),
+ )
+ newServerSession := func(session Session) error {
+ return newSessionCallback(session, &serverMsgHandler)
+ }
+ server.RunEventLoop(newServerSession)
+ assert.True(t, server.ID() > 0)
+ assert.True(t, server.EndPointType() == TCP_SERVER)
+ assert.NotNil(t, server.streamListener)
+ }()
+ time.Sleep(500e6)
+
+ addr := server.streamListener.Addr().String()
+ t.Logf("@address:%s, tcp server addr: %v", address, addr)
+ keyPath, _ := filepath.Abs("./demo/hello/tls/certs/ca.key")
+ clientCaPemPath, _ := filepath.Abs("./demo/hello/tls/certs/ca.pem")
+
+ clientConfig := &ClientTlsConfigBuilder{
+ ClientTrustCertCollectionPath: clientCaPemPath,
+ ClientPrivateKeyPath: keyPath,
+ }
+
+ clt := newClient(TCP_CLIENT,
+ WithServerAddress(addr),
+ WithReconnectInterval(5e8),
+ WithConnectionNumber(1),
+ WithClientTlsConfigBuilder(clientConfig),
+ )
+ assert.NotNil(t, clt)
+ assert.True(t, clt.ID() > 0)
+ assert.Equal(t, clt.endPointType, TCP_CLIENT)
+
+ var (
+ msgHandler MessageHandler
+ )
+ cb := func(session Session) error {
+ return newSessionCallback(session, &msgHandler)
+ }
+
+ clt.RunEventLoop(cb)
+ time.Sleep(1e9)
+
+ assert.Equal(t, 1, msgHandler.SessionNumber())
+ clt.Close()
+ assert.True(t, clt.IsClosed())
+
+ server.Close()
+ assert.True(t, server.IsClosed())
+}
func testUDPServer(t *testing.T, address string) {
var (
@@ -113,4 +183,6 @@
addr = "127.0.0.1"
testTCPServer(t, addr)
testUDPServer(t, addr)
+ addr = "127.0.0.9999"
+ testTCPTlsServer(t, addr)
}
diff --git a/tls.go b/tls.go
new file mode 100644
index 0000000..4673511
--- /dev/null
+++ b/tls.go
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package getty
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "io/ioutil"
+)
+import (
+ perrors "github.com/pkg/errors"
+)
+
+type TlsConfigBuilder interface {
+ BuildTlsConfig() (*tls.Config, error)
+}
+
+type ServerTlsConfigBuilder struct {
+ ServerKeyCertChainPath string
+ ServerPrivateKeyPath string
+ ServerKeyPassword string
+ ServerTrustCertCollectionPath string
+}
+
+func (s *ServerTlsConfigBuilder) BuildTlsConfig() (*tls.Config, error) {
+ var (
+ err error
+ certPem []byte
+ certificate tls.Certificate
+ certPool *x509.CertPool
+ config *tls.Config
+ )
+ if certificate, err = tls.LoadX509KeyPair(s.ServerKeyCertChainPath, s.ServerPrivateKeyPath); err != nil {
+ log.Error(fmt.Sprintf("tls.LoadX509KeyPair(certs{%s}, privateKey{%s}) = err:%+v",
+ s.ServerKeyCertChainPath, s.ServerPrivateKeyPath, perrors.WithStack(err)))
+ return nil, err
+ }
+ config = &tls.Config{
+ InsecureSkipVerify: true, // do not verify peer certs
+ ClientAuth: tls.RequireAnyClientCert,
+ Certificates: []tls.Certificate{certificate},
+ }
+
+ if s.ServerTrustCertCollectionPath != "" {
+ certPem, err = ioutil.ReadFile(s.ServerTrustCertCollectionPath)
+ if err != nil {
+ log.Error(fmt.Errorf("ioutil.ReadFile(certFile{%s}) = err:%+v", s.ServerTrustCertCollectionPath, perrors.WithStack(err)))
+ return nil, err
+ }
+ certPool = x509.NewCertPool()
+ if ok := certPool.AppendCertsFromPEM(certPem); !ok {
+ log.Error("failed to parse root certificate file")
+ return nil, err
+ }
+ config.ClientCAs = certPool
+ config.ClientAuth = tls.RequireAnyClientCert
+ config.InsecureSkipVerify = false
+ }
+ return config, nil
+}
+
+type ClientTlsConfigBuilder struct {
+ ClientKeyCertChainPath string
+ ClientPrivateKeyPath string
+ ClientKeyPassword string
+ ClientTrustCertCollectionPath string
+}
+
+func (c *ClientTlsConfigBuilder) BuildTlsConfig() (*tls.Config, error) {
+
+ cert, err := tls.LoadX509KeyPair(c.ClientTrustCertCollectionPath, c.ClientPrivateKeyPath)
+ if err != nil {
+ log.Error(fmt.Sprintf("Unable to load X509 Key Pair %v", err))
+ return nil, err
+ }
+ certBytes, err := ioutil.ReadFile(c.ClientTrustCertCollectionPath)
+ if err != nil {
+ log.Error(fmt.Sprintf("Unable to read pem file: %s", c.ClientTrustCertCollectionPath))
+ return nil, err
+ }
+ clientCertPool := x509.NewCertPool()
+ ok := clientCertPool.AppendCertsFromPEM(certBytes)
+ if !ok {
+ log.Error("failed to parse root certificate")
+ return nil, err
+ }
+ return &tls.Config{
+ RootCAs: clientCertPool,
+ Certificates: []tls.Certificate{cert},
+ InsecureSkipVerify: true,
+ }, nil
+}