aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2019-06-22 01:45:37 -0400
committerDeterminant <ted.sybil@gmail.com>2019-06-22 01:45:37 -0400
commit66914cd88bd822d3399e754f43a42906c043f1fd (patch)
tree77751cf4f2b106cb8fe2dd66f546502a7a099217
parent988748a02d39228017e36f7a5c3415b19b31657d (diff)
support TLS; change some API
-rw-r--r--Makefile5
-rw-r--r--crypto.go94
-rw-r--r--network.go88
m---------salticidae0
-rw-r--r--stream.go53
-rw-r--r--test_msgnet/main.go12
-rw-r--r--test_msgnet_tls/alice.pem83
-rw-r--r--test_msgnet_tls/bob.pem83
-rw-r--r--test_msgnet_tls/main.go171
-rw-r--r--test_p2p_stress/main.go18
10 files changed, 568 insertions, 39 deletions
diff --git a/Makefile b/Makefile
index 4e2b0cb..7ac8971 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
.PHONY: all clean
-all: build/test_msgnet build/test_p2p_stress
+all: build/test_msgnet build/test_p2p_stress build/test_msgnet_tls
salticidae/libsalticidae.so:
@@ -13,6 +13,9 @@ build:
build/test_msgnet: salticidae/libsalticidae.so test_msgnet/main.go
make -C salticidae/
go build -o $@ github.com/Determinant/salticidae-go/test_msgnet
+build/test_msgnet_tls: salticidae/libsalticidae.so test_msgnet_tls/main.go
+ make -C salticidae/
+ go build -o $@ github.com/Determinant/salticidae-go/test_msgnet_tls
build/test_p2p_stress: salticidae/libsalticidae.so test_p2p_stress/main.go
make -C salticidae/
go build -o $@ github.com/Determinant/salticidae-go/test_p2p_stress
diff --git a/crypto.go b/crypto.go
new file mode 100644
index 0000000..528be5c
--- /dev/null
+++ b/crypto.go
@@ -0,0 +1,94 @@
+package salticidae
+
+// #include <stdlib.h>
+// #include "salticidae/crypto.h"
+import "C"
+import "runtime"
+
+// The C pointer type for a X509 handle.
+type CX509 = *C.x509_t
+type x509 struct { inner CX509 }
+// The handle for a X509 certificate.
+type X509 = *x509
+
+func NewX509FromPemFile(fname string, passwd *string, err *Error) X509 {
+ fname_c_str := C.CString(fname)
+ passwd_c_str := (*C.char)(nil)
+ if passwd != nil {
+ passwd_c_str = C.CString(*passwd)
+ }
+ res := &x509{ inner: C.x509_new_from_pem_file(fname_c_str, passwd_c_str, err) }
+ if res != nil {
+ runtime.SetFinalizer(res, func(self X509) { self.free() })
+ }
+ C.free(rawptr_t(fname_c_str))
+ if passwd_c_str != nil {
+ C.free(rawptr_t(passwd_c_str))
+ }
+ return res
+}
+
+func NewX509FromDer(der ByteArray, err *Error) X509 {
+ res := &x509{ inner: C.x509_new_from_der(der.inner, err) }
+ if res != nil {
+ runtime.SetFinalizer(res, func(self X509) { self.free() })
+ }
+ return res
+}
+
+func (self X509) free() { C.x509_free(self.inner) }
+func (self X509) GetPubKey() PKey {
+ res := &pKey{ inner: C.x509_get_pubkey(self.inner) }
+ runtime.SetFinalizer(res, func(self PKey) { self.free() })
+ return res
+}
+
+func (self X509) GetDer() ByteArray {
+ res := &byteArray{ inner: C.x509_get_der(self.inner) }
+ runtime.SetFinalizer(res, func(self ByteArray) { self.free() })
+ return res
+}
+
+// The C pointer type for a PKey handle.
+type CPKey = *C.pkey_t
+type pKey struct { inner CPKey }
+// The handle for an OpenSSL EVP_PKEY.
+type PKey = *pKey
+
+func NewPrivKeyFromPemFile(fname string, passwd *string, err *Error) PKey {
+ fname_c_str := C.CString(fname)
+ passwd_c_str := (*C.char)(nil)
+ if passwd != nil {
+ passwd_c_str = C.CString(*passwd)
+ }
+ res := &pKey{ inner: C.pkey_new_privkey_from_pem_file(fname_c_str, passwd_c_str, err) }
+ if res != nil {
+ runtime.SetFinalizer(res, func(self PKey) { self.free() })
+ }
+ C.free(rawptr_t(fname_c_str))
+ if passwd_c_str != nil {
+ C.free(rawptr_t(passwd_c_str))
+ }
+ return res
+}
+
+func NewPrivKeyFromDer(der ByteArray, err *Error) PKey {
+ res := &pKey{ inner: C.pkey_new_privkey_from_der(der.inner, err) }
+ if res != nil {
+ runtime.SetFinalizer(res, func(self PKey) { self.free() })
+ }
+ return res
+}
+
+func (self PKey) free() { C.pkey_free(self.inner) }
+func (self PKey) GetPubKeyDer() ByteArray {
+ res := &byteArray{ inner: C.pkey_get_pubkey_der(self.inner) }
+ runtime.SetFinalizer(res, func(self ByteArray) { self.free() })
+ return res
+}
+
+func (self PKey) GetPrivKeyDer() ByteArray {
+ res := &byteArray{ inner: C.pkey_get_privkey_der(self.inner) }
+ runtime.SetFinalizer(res, func(self ByteArray) { self.free() })
+ return res
+}
diff --git a/network.go b/network.go
index 0440326..5880cc9 100644
--- a/network.go
+++ b/network.go
@@ -1,5 +1,6 @@
package salticidae
+// #include <stdlib.h>
// #include "salticidae/network.h"
import "C"
import "runtime"
@@ -59,6 +60,13 @@ func (self MsgNetworkConn) GetAddr() NetAddr {
return NetAddrFromC(C.msgnetwork_conn_get_addr(self.inner))
}
+// Get the certificate of the remote end of this connection. Use Copy() to make a
+// copy of the certificate if you want to use the certificate object beyond the
+// lifetime of the connection.
+func (self MsgNetworkConn) GetPeerCert() X509 {
+ return &x509{ inner: C.msgnetwork_conn_get_peer_cert(self.inner) }
+}
+
// Make a copy of the object. This is required if you want to keep the
// connection passed as a callback parameter by other salticidae methods (such
// like MsgNetwork/PeerNetwork).
@@ -95,36 +103,76 @@ func (self MsgNetworkConfig) BurstSize(size int) {
C.msgnetwork_config_burst_size(self.inner, C.size_t(size))
}
-// Maximum backlogs (see POSIX TCP backlog).
+// Set the maximum backlogs (see POSIX TCP backlog).
func (self MsgNetworkConfig) MaxListenBacklog(backlog int) {
C.msgnetwork_config_max_listen_backlog(self.inner, C.int(backlog))
}
-// The timeout for connecting to the remote (in seconds).
+// Set the timeout for connecting to the remote (in seconds).
func (self MsgNetworkConfig) ConnServerTimeout(timeout float64) {
C.msgnetwork_config_conn_server_timeout(self.inner, C.double(timeout))
}
-// The size for an inbound data chunk (per read() syscall).
+// Set the size for an inbound data chunk (per read() syscall).
func (self MsgNetworkConfig) SegBuffSize(size int) {
C.msgnetwork_config_seg_buff_size(self.inner, C.size_t(size))
}
-// The number of worker threads.
+// Set the number of worker threads.
func (self MsgNetworkConfig) NWorker(nworker int) {
C.msgnetwork_config_nworker(self.inner, C.size_t(nworker))
}
-// The capacity of the send buffer.
+// Set the capacity of the send buffer.
func (self MsgNetworkConfig) QueueCapacity(capacity int) {
C.msgnetwork_config_queue_capacity(self.inner, C.size_t(capacity))
}
+// Specify whether to use SSL/TLS. When this flag is enabled, MsgNetwork uses
+// TLSKey (or TLSKeyFile) or TLSCert (or TLSCertFile) to setup the underlying
+// OpenSSL.
+func (self MsgNetworkConfig) EnableTLS(enabled bool) {
+ C.msgnetwork_config_enable_tls(self.inner, C.bool(enabled))
+}
+
+// Load the TLS key from a file. The file should be an unencrypted PEM file.
+// Use TLSKey() instead for more complex usage.
+func (self MsgNetworkConfig) TLSKeyFile(fname string) {
+ c_str := C.CString(fname)
+ C.msgnetwork_config_tls_key_file(self.inner, c_str)
+ C.free(rawptr_t(c_str))
+}
+
+// Load the TLS certificate from a file. The file should be an unencrypted
+// (X509) PEM file. Use TLSCert() instead for more complex usage.
+func (self MsgNetworkConfig) TLSCertFile(fname string) {
+ c_str := C.CString(fname)
+ C.msgnetwork_config_tls_cert_file(self.inner, c_str)
+ C.free(rawptr_t(c_str))
+}
+
+// Use the given TLS key. This overrides TLSKeyFile(). pkey will be moved and
+// kept by the library. Thus, no methods of msg involving the payload should be
+// called afterwards.
+func (self MsgNetworkConfig) TLSKeyByMove(pkey PKey) {
+ C.msgnetwork_config_tls_key_by_move(self.inner, pkey.inner)
+}
+
+//// Load the TLS certificate from a file. The file should be an unencrypted
+//// (X509) PEM file. Use TLSCert() instead for more complex usage.
+//func (self MsgNetworkConfig) TLSCert(fname string) {
+// c_str := C.CString(fname)
+// C.msgnetwork_config_tls_cert(self.inner, c_str)
+// C.free(rawptr_t(c_str))
+//}
+
// Create a message network handle which is attached to given event loop.
-func NewMsgNetwork(ec EventContext, config MsgNetworkConfig) MsgNetwork {
- res := MsgNetworkFromC(C.msgnetwork_new(ec.inner, config.inner))
- ec.attach(rawptr_t(res.inner), res)
- runtime.SetFinalizer(res, func(self MsgNetwork) { self.free() })
+func NewMsgNetwork(ec EventContext, config MsgNetworkConfig, err *Error) MsgNetwork {
+ res := MsgNetworkFromC(C.msgnetwork_new(ec.inner, config.inner, err))
+ if res != nil {
+ ec.attach(rawptr_t(res.inner), res)
+ runtime.SetFinalizer(res, func(self MsgNetwork) { self.free() })
+ }
return res
}
@@ -155,9 +203,11 @@ func (self MsgNetwork) SendMsgDeferredByMove(msg Msg, conn MsgNetworkConn) {
// Try to connect to a remote address. The connection handle is returned. The
// returned connection handle could be kept in your program.
-func (self MsgNetwork) Connect(addr NetAddr, err *Error) MsgNetworkConn {
- res := MsgNetworkConnFromC(C.msgnetwork_connect(self.inner, addr.inner, err))
- runtime.SetFinalizer(res, func(self MsgNetworkConn) { self.free() })
+func (self MsgNetwork) Connect(addr NetAddr, blocking bool, err *Error) MsgNetworkConn {
+ res := MsgNetworkConnFromC(C.msgnetwork_connect(self.inner, addr.inner, C.bool(blocking), err))
+ if res != nil {
+ runtime.SetFinalizer(res, func(self MsgNetworkConn) { self.free() })
+ }
return res
}
@@ -269,10 +319,12 @@ func (self PeerNetworkConfig) AsMsgNetworkConfig() MsgNetworkConfig {
}
// Create a peer-to-peer message network handle.
-func NewPeerNetwork(ec EventContext, config PeerNetworkConfig) PeerNetwork {
- res := PeerNetworkFromC(C.peernetwork_new(ec.inner, config.inner))
- ec.attach(rawptr_t(res.inner), res)
- runtime.SetFinalizer(res, func(self PeerNetwork) { self.free() })
+func NewPeerNetwork(ec EventContext, config PeerNetworkConfig, err *Error) PeerNetwork {
+ res := PeerNetworkFromC(C.peernetwork_new(ec.inner, config.inner, err))
+ if res != nil {
+ ec.attach(rawptr_t(res.inner), res)
+ runtime.SetFinalizer(res, func(self PeerNetwork) { self.free() })
+ }
return res
}
@@ -290,7 +342,9 @@ func (self PeerNetwork) HasPeer(paddr NetAddr) bool { return bool(C.peernetwork_
// returned connection handle could be kept in your program.
func (self PeerNetwork) GetPeerConn(paddr NetAddr, err *Error) PeerNetworkConn {
res := PeerNetworkConnFromC(C.peernetwork_get_peer_conn(self.inner, paddr.inner, err))
- runtime.SetFinalizer(res, func(self PeerNetworkConn) { self.free() })
+ if res != nil {
+ runtime.SetFinalizer(res, func(self PeerNetworkConn) { self.free() })
+ }
return res
}
diff --git a/salticidae b/salticidae
-Subproject ff904b23147e72db4f7f77f8269242d9a5a0859
+Subproject da9410b41cf56340fd4a3e5148df704c9c0e139
diff --git a/stream.go b/stream.go
index c35933e..bbc7680 100644
--- a/stream.go
+++ b/stream.go
@@ -30,6 +30,14 @@ func NewByteArrayMovedFromDataStream(src DataStream) ByteArray {
return res
}
+func NewByteArrayFromHex(hex string) ByteArray {
+ c_str := C.CString(hex)
+ res := &byteArray{ inner: C.bytearray_new_from_hex(c_str) }
+ C.free(rawptr_t(c_str))
+ runtime.SetFinalizer(res, func(self ByteArray) { self.free() })
+ return res
+}
+
// The C pointer to a DataStream object.
type CDataStream = *C.datastream_t
type dataStream struct {
@@ -47,11 +55,17 @@ func DataStreamFromC(ptr CDataStream) DataStream {
}
}
+func dataStreamSetFinalizer(res DataStream) DataStream {
+ if res != nil {
+ runtime.SetFinalizer(res, func(self DataStream) { self.free() })
+ }
+ return res
+}
+
// Create an empty DataStream.
func NewDataStream() DataStream {
res := DataStreamFromC(C.datastream_new())
- runtime.SetFinalizer(res, func(self DataStream) { self.free() })
- return res
+ return dataStreamSetFinalizer(res)
}
// Create a DataStream with data copied from bytes.
@@ -63,7 +77,20 @@ func NewDataStreamFromBytes(bytes []byte) (res DataStream) {
} else {
res = DataStreamFromC(C.datastream_new())
}
- runtime.SetFinalizer(res, func(self DataStream) { self.free() })
+ return dataStreamSetFinalizer(res)
+}
+
+// Create a DataStream with content moved from a ByteArray.
+func NewDataStreamMovedFromByteArray(bytes ByteArray) (res DataStream) {
+ res = DataStreamFromC(C.datastream_new_moved_from_bytearray(bytes.inner))
+ dataStreamSetFinalizer(res)
+ return
+}
+
+// Create a DataStream with content copied from a ByteArray.
+func NewDataStreamFromByteArray(bytes ByteArray) (res DataStream) {
+ res = DataStreamFromC(C.datastream_new_from_bytearray(bytes.inner))
+ dataStreamSetFinalizer(res)
return
}
@@ -75,8 +102,7 @@ func (self DataStream) detach(ptr rawptr_t) { delete(self.attached, uintptr(ptr)
// Make a copy of the object.
func (self DataStream) Copy() DataStream {
res := DataStreamFromC(C.datastream_copy(self.inner))
- runtime.SetFinalizer(res, func(self DataStream) { self.free() })
- return res
+ return dataStreamSetFinalizer(res)
}
// TODO: datastream_data
@@ -166,7 +192,17 @@ type UInt256 = *uint256
// Create a 256-bit integer.
func NewUInt256() UInt256 {
res := &uint256{ inner: C.uint256_new() }
- runtime.SetFinalizer(res, func(self UInt256) { self.free() })
+ if res != nil {
+ runtime.SetFinalizer(res, func(self UInt256) { self.free() })
+ }
+ return res
+}
+
+func NewUInt256FromByteArray(bytes ByteArray) UInt256 {
+ res := &uint256{ inner: C.uint256_new_from_bytearray(bytes.inner) }
+ if res != nil {
+ runtime.SetFinalizer(res, func(self UInt256) { self.free() })
+ }
return res
}
@@ -191,6 +227,11 @@ func (self DataStream) GetHash() UInt256 {
return res
}
+// Get the Sha256 hash of the given ByteArray content.
+func (self ByteArray) GetHash() UInt256 {
+ return NewDataStreamFromByteArray(self).GetHash()
+}
+
// Get hexadicemal string representation of the given DataStream content
// (without consuming the stream).
func (self DataStream) GetHex() string {
diff --git a/test_msgnet/main.go b/test_msgnet/main.go
index 66d7287..065b773 100644
--- a/test_msgnet/main.go
+++ b/test_msgnet/main.go
@@ -113,7 +113,7 @@ func connHandler(_conn *C.struct_msgnetwork_conn_t, connected C.bool, _ unsafe.P
} else {
fmt.Printf("[%s] Disconnected, retrying.\n", name)
err := salticidae.NewError()
- net.Connect(conn.GetAddr(), &err)
+ net.Connect(conn.GetAddr(), false, &err)
}
}
@@ -127,20 +127,18 @@ func errorHandler(_err *C.struct_SalticidaeCError, fatal C.bool, _ unsafe.Pointe
func genMyNet(ec salticidae.EventContext, name string,
myAddr salticidae.NetAddr, otherAddr salticidae.NetAddr) MyNet {
+ err := salticidae.NewError()
netconfig := salticidae.NewMsgNetworkConfig()
- n := MyNet {
- net: salticidae.NewMsgNetwork(ec, netconfig),
- name: name,
- }
+ net := salticidae.NewMsgNetwork(ec, netconfig, &err); checkError(&err)
+ n := MyNet { net: net, name: name }
n.net.RegHandler(MSG_OPCODE_HELLO, salticidae.MsgNetworkMsgCallback(C.onReceiveHello), nil)
n.net.RegHandler(MSG_OPCODE_ACK, salticidae.MsgNetworkMsgCallback(C.onReceiveAck), nil)
n.net.RegConnHandler(salticidae.MsgNetworkConnCallback(C.connHandler), nil)
n.net.RegErrorHandler(salticidae.MsgNetworkErrorCallback(C.errorHandler), nil)
n.net.Start()
- err := salticidae.NewError()
n.net.Listen(myAddr, &err); checkError(&err)
- n.net.Connect(otherAddr, &err); checkError(&err)
+ n.net.Connect(otherAddr, false, &err); checkError(&err)
return n
}
diff --git a/test_msgnet_tls/alice.pem b/test_msgnet_tls/alice.pem
new file mode 100644
index 0000000..6efe00f
--- /dev/null
+++ b/test_msgnet_tls/alice.pem
@@ -0,0 +1,83 @@
+-----BEGIN PRIVATE KEY-----
+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
+THSAjGzVtLewAwo0qkl141+539oWDw==
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIUFitZjQ11n2jQiX7GPH5RtQorw1gwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTA2MjEwMjU5MThaFw0xOTA3
+MjEwMjU5MThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDZFKh7iaGPvfvh6qYrQN0Twq9nnpukjHYG+Zjuq/6T
+/JgMVezRXDA6e6nPH1va6tRzi+MsJ4Ues7alm6ddnxNgUOI2ROl9G6Gmx68Y75BG
+R1vKMUw7ujz8flaXYFO5mASSbE87pI5F/Hm/7k0Ke47rEE6Ke1iARcv0pW9loFT8
+y00NBXg/IQSUSb1riDXOHVK3fY8xHN5w5/pXwaLNpqTByKOPcBCQhJBWh83n09vY
+ysDEFzJC3QUvNWNCUttbgexqY8hJO4jP5SD+DmSiPw+6gNiyJdPdvmY+VgDXtd1d
+1ApihkiLlSa3EhQAMbS6ajM3NuwS5ikpnZ5cNDvGuBS4XQx8R+X93Q1xyeclNVkd
+2bFj0rdjfIxyurl8Nziq2/NM/AVCtBXCdGDO8aFnivPlA/FtfKbfuhhNVWts0ODL
+HR8dd5AZpGjtgZBJiXW97XQOeG0hDp8WwBNns0UFEewkMOMX1ByA7ZWeOSiJHe+l
+cmVEs7RaUcEhs5OK/sgAo3Ig+4mO0z6VH8gp/WxP8ce+5xA6cTao2wJn3N1ux4Oq
+4fqZXR3rPh7IcEkHCyBKL1jxiUmPlIXvmED2PzyWSxyoDTm9w1TBLamD0Usdd1P9
+9Rclgri3erhr6kT4YnWV0WMqrsP3ZserGTkm3Gsi6s6X9sTdu3Yi/P4N2nvRPZOB
+0wIDAQABo1MwUTAdBgNVHQ4EFgQU/dKIin9ueRiA5tqyKmD9w0g4TVAwHwYDVR0j
+BBgwFoAU/dKIin9ueRiA5tqyKmD9w0g4TVAwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEANGM+fUoMyYkbdSRhocIJ/WZo3fb96289SsDmVrwQyazn
+4O0MPlgz2y6RXQf0rDr0xQ9jj0hv6UEpVcaUdVrgRYJzW7YviN6x/urqsJNtVUJb
+t6xF+IS+ibT4OulJlQyJlYX0opQQzVQGgKW8jwetPdBNVtoH5j7AZaCYhlOnOz6r
+JpA07sI3fSuVb0NjDuHPgzR139r1IlpBLP/OmkG4LH19tP9Ad78Dehl7K/TA2Rwr
+i3wZk77Wvbz7u5ZMqHxxdS4opUWYnpyApeudFNiXRS1ls7R7lJZE3+9OKT9EcVd+
+GwJzWJVvtqXotOqfjYVWj4EFebH9MAdb34l7F1OgyKQ3Nmw7BzuQ7XdoKn5/DL5Q
+b9PeRSnWpzgaSEj341GlZL1fs2IY+KYxHB3XeptDgAIPRP7+Q39/FRKGyuxTX2l/
+7a1jIN7xRF15mqpEzbICch+RXv9hMMHqMr7H8psQXKbQTFZkZatwPneho1T6E58o
+JLjQME1bOMR++forya9rZZCl11io3OitFbzewBmMdPCcA5fJS13MW7jJ6x41L/lw
+d6qBH3eG2paTc+aVRIaJhhwR/ommpILiU8X/kXq6StLGB1YD5Jm0KvREyME/o0U7
+sT/91lpmMtRtwqaIOTZbUn1vEmS3aHZKS5q+Vs/eYZm3exF/L+Bzy40vn9wxU0I=
+-----END CERTIFICATE-----
diff --git a/test_msgnet_tls/bob.pem b/test_msgnet_tls/bob.pem
new file mode 100644
index 0000000..8f8afcc
--- /dev/null
+++ b/test_msgnet_tls/bob.pem
@@ -0,0 +1,83 @@
+-----BEGIN PRIVATE KEY-----
+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
+HHHAbLi3XqeKbfEWQL0METvL2SBhlAA=
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIUTfDNmCzLkU+iC/fDlcG2P7Z2iXMwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTA2MjEwMzI4MjVaFw0xOTA3
+MjEwMzI4MjVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDfnQZzGUUL/pQN4g3U7fI6DHsvy6AztawB89m5nbXO
+FA9YGiFpzTGByZ6xAJRRnoz5HtbwjbkAYiUcG+sbGF7RSDAchAOC0EYKK8YQd/kG
+YzD/mIFzyzRSk1Kpc/SSIDKmuO9iFWfNSOqIzfkE8M0hV2vwbZ/tZfi/ToP8nH7Z
+llpa6E2SQhQRDsojMPSyMkP2uYvBL9CjRbZzgsVPaHItfQkP5c3+oNTgTNbv6HwI
+98h2xXYIAL8MKg7B/xj8BXczf9KGhWNCcRn/ci+wME08e9+FZUH1JYIQgRAu1Q7e
+Gp5JhGl4Tls9/YTH7FFVTbpZZaoRj95mMKVTzrXOlSdiQcAuAnfKvSm733tK9VL/
+JFFWfrscWaWONKUEogW988hQ7xg+0VQ5BBd3/S6yT/0fUjVLwM2hoJguQFtNkuBd
+eT7Bp+cVO0uI+g1sPFV3+0XC0Z5MytwedS+0BSq3KBheQ/FBTDZ8wHk9H1fPbNX4
+va1dj4bw2D5vuQL1gYTSIV5yUARakt78qH9s9+gkUfJGjtiI8FBbF5p4AhbBpKD0
+dhy7Pbkzw3zaWGCxOATUXTxiB9qgLwjancaxx1XegMB8ZhjoNjUzX1iBh11Sejmq
+v0Sv1PLdAgzxlIVfaIkf/wyQwX/GGbqN7ne/J+lk2DIe3ynxn6FmIdvtfrFbbCGp
+xQIDAQABo1MwUTAdBgNVHQ4EFgQUX/c1vXnm9tkgHTZndvy5PzgoupIwHwYDVR0j
+BBgwFoAUX/c1vXnm9tkgHTZndvy5PzgoupIwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEAhUik2ITFpR8s571Ds1jNr/kvM3j1dwG1qCIN7GuE4XuV
+0vS6W2FCeBfB/WPvf9HCQFNR9l9npPI27BJA1J853ywlzj6WyfiA9Fv517aOMCs+
+PaySYcM23Hyyi3sSAdNYWlnQg0JUI1kdIMb3dileleDz2Eh6IxIugpvZ3s+7bOiN
+H2FkOrzMq/w8aJ+kUk8IyGToxtBVvmjbINRK0bgANHJOifzp5ASYqvEZAcggot1n
+pvVToqGDxtuuVd4qX8/DXPCVooOJ0RAcGZ44+hXfN1T5icPmnqMLuoPx9qiUZO+T
+PIHg2DknmZSEunyy4LO5SiEsQVBzL3v8voYIqoobBuB5A2wyG9BXT5c3OM2rxDkX
+UfXjxMdiGu3+iOaGE0KePXVY6oy3vgbmaowh5n8ZN6sN8aJPty3ZdpYpRPXKJsft
+DtTH5sITHiisU2+rV2kJMKyASrxPWJAxkelahbUacOzid83TG+uqBCUJY0YPLRsF
+TCvZ/jqJ8PNXFiZWnfyVkH3qFNjzQ595xMLe5fE5p/pCEV7aqHI0Ds9VYy82IJAT
+070s/gtoLj5DussTetb9rh7Nt9ndJ5T7vvL9aeSmulRs2Z1j6u7rTvo4TjAbLbxx
+bCR8r/T+5G0F9qLC6o4C2kFfZSiogxtM8n6tCJzzpWnpMwVad0a+GuH4tdNFsQA=
+-----END CERTIFICATE-----
diff --git a/test_msgnet_tls/main.go b/test_msgnet_tls/main.go
new file mode 100644
index 0000000..c45cfdf
--- /dev/null
+++ b/test_msgnet_tls/main.go
@@ -0,0 +1,171 @@
+package main
+
+// #cgo CFLAGS: -I${SRCDIR}/../salticidae/include/
+// #include <stdlib.h>
+// #include "salticidae/network.h"
+// void onTerm(int sig, void *);
+// void onReceiveHello(msg_t *, msgnetwork_conn_t *, void *);
+// void onReceiveAck(msg_t *, msgnetwork_conn_t *, void *);
+// bool connHandler(msgnetwork_conn_t *, bool, void *);
+// void errorHandler(SalticidaeCError *, bool, void *);
+import "C"
+
+import (
+ "encoding/binary"
+ "os"
+ "fmt"
+ "unsafe"
+ "github.com/Determinant/salticidae-go"
+)
+
+const (
+ MSG_OPCODE_HELLO salticidae.Opcode = iota
+ MSG_OPCODE_ACK
+)
+
+func msgHelloSerialize(name string, text string) salticidae.Msg {
+ serialized := salticidae.NewDataStream()
+ t := make([]byte, 4)
+ binary.LittleEndian.PutUint32(t, uint32(len(name)))
+ serialized.PutData(t)
+ serialized.PutData([]byte(name))
+ serialized.PutData([]byte(text))
+ return salticidae.NewMsgMovedFromByteArray(
+ MSG_OPCODE_HELLO, salticidae.NewByteArrayMovedFromDataStream(serialized))
+}
+
+func msgHelloUnserialize(msg salticidae.Msg) (name string, text string) {
+ p := msg.GetPayloadByMove()
+ t := p.GetDataInPlace(4); length := binary.LittleEndian.Uint32(t.Get()); t.Release()
+ t = p.GetDataInPlace(int(length)); name = string(t.Get()); t.Release()
+ t = p.GetDataInPlace(p.Size()); text = string(t.Get()); t.Release()
+ return
+}
+
+func msgAckSerialize() salticidae.Msg {
+ return salticidae.NewMsgMovedFromByteArray(MSG_OPCODE_ACK, salticidae.NewByteArray())
+}
+
+func checkError(err *salticidae.Error) {
+ if err.GetCode() != 0 {
+ fmt.Printf("error during a sync call: %s\n", salticidae.StrError(err.GetCode()))
+ os.Exit(1)
+ }
+}
+
+type MyNet struct {
+ net salticidae.MsgNetwork
+ name string
+ peerCert salticidae.UInt256
+ cname *C.char
+}
+
+var (
+ alice, bob MyNet
+ ec salticidae.EventContext
+)
+
+//export onTerm
+func onTerm(_ C.int, _ unsafe.Pointer) {
+ ec.Stop()
+}
+
+//export onReceiveHello
+func onReceiveHello(_msg *C.struct_msg_t, _conn *C.struct_msgnetwork_conn_t, userdata unsafe.Pointer) {
+ msg := salticidae.MsgFromC(salticidae.CMsg(_msg))
+ conn := salticidae.MsgNetworkConnFromC(salticidae.CMsgNetworkConn(_conn))
+ net := conn.GetNet()
+ name, text := msgHelloUnserialize(msg)
+ myName := C.GoString((*C.char)(userdata))
+ fmt.Printf("[%s] %s says %s\n", myName, name, text)
+ ack := msgAckSerialize()
+ net.SendMsg(ack, conn)
+}
+
+//export onReceiveAck
+func onReceiveAck(_ *C.struct_msg_t, _conn *C.struct_msgnetwork_conn_t, userdata unsafe.Pointer) {
+ myName := C.GoString((*C.char)(userdata))
+ fmt.Printf("[%s] the peer knows\n", myName)
+}
+
+//export connHandler
+func connHandler(_conn *C.struct_msgnetwork_conn_t, connected C.bool, userdata unsafe.Pointer) C.bool {
+ conn := salticidae.MsgNetworkConnFromC(salticidae.CMsgNetworkConn(_conn))
+ net := conn.GetNet()
+ myName := C.GoString((*C.char)(userdata))
+ n := alice
+ if myName == "bob" { n = bob }
+ res := true
+ if connected {
+ certHash := conn.GetPeerCert().GetDer().GetHash()
+ res = certHash.IsEq(n.peerCert)
+ if conn.GetMode() == salticidae.CONN_MODE_ACTIVE {
+ fmt.Printf("[%s] Connected, sending hello.\n", myName)
+ hello := msgHelloSerialize(myName, "Hello there!")
+ n.net.SendMsg(hello, conn)
+ } else {
+ status := "fail"
+ if res { status = "ok" }
+ fmt.Printf("[%s] Accepted, waiting for greetings.\n" +
+ "The peer certificate footprint is %s (%s)\n",
+ myName, certHash.GetHex(), status)
+ }
+ } else {
+ fmt.Printf("[%s] Disconnected, retrying.\n", myName)
+ err := salticidae.NewError()
+ net.Connect(conn.GetAddr(), false, &err)
+ }
+ return C.bool(res)
+}
+
+//export errorHandler
+func errorHandler(_err *C.struct_SalticidaeCError, fatal C.bool, _ unsafe.Pointer) {
+ err := (*salticidae.Error)(unsafe.Pointer(_err))
+ s := "recoverable"
+ if fatal { s = "fatal" }
+ fmt.Printf("Captured %s error during an async call: %s\n", s, salticidae.StrError(err.GetCode()))
+}
+
+func genMyNet(ec salticidae.EventContext,
+ name string, peerCert string,
+ myAddr salticidae.NetAddr, otherAddr salticidae.NetAddr) MyNet {
+ err := salticidae.NewError()
+ netconfig := salticidae.NewMsgNetworkConfig()
+ netconfig.EnableTLS(true)
+ netconfig.TLSKeyFile(name + ".pem")
+ netconfig.TLSCertFile(name + ".pem")
+ net := salticidae.NewMsgNetwork(ec, netconfig, &err); checkError(&err)
+ _peerCert := salticidae.NewUInt256FromByteArray(salticidae.NewByteArrayFromHex(peerCert))
+ cname := C.CString(name)
+ n := MyNet { net: net, name: name, peerCert: _peerCert, cname: cname }
+ n.net.RegHandler(MSG_OPCODE_HELLO, salticidae.MsgNetworkMsgCallback(C.onReceiveHello), unsafe.Pointer(cname))
+ n.net.RegHandler(MSG_OPCODE_ACK, salticidae.MsgNetworkMsgCallback(C.onReceiveAck), unsafe.Pointer(cname))
+ n.net.RegConnHandler(salticidae.MsgNetworkConnCallback(C.connHandler), unsafe.Pointer(cname))
+ n.net.RegErrorHandler(salticidae.MsgNetworkErrorCallback(C.errorHandler), unsafe.Pointer(cname))
+
+ n.net.Start()
+ n.net.Listen(myAddr, &err); checkError(&err)
+ n.net.Connect(otherAddr, false, &err); checkError(&err)
+ return n
+}
+
+func main() {
+ ec = salticidae.NewEventContext()
+
+ aliceAddr := salticidae.NewAddrFromIPPortString("127.0.0.1:12345")
+ bobAddr := salticidae.NewAddrFromIPPortString("127.0.0.1:12346")
+
+ alice = genMyNet(ec, "alice", "ed5a9a8c7429dcb235a88244bc69d43d16b35008ce49736b27aaa3042a674043", aliceAddr, bobAddr)
+ bob = genMyNet(ec, "bob", "ef3bea4e72f4d0e85da7643545312e2ff6dded5e176560bdffb1e53b1cef4896", bobAddr, aliceAddr)
+
+ ev_int := salticidae.NewSigEvent(ec, salticidae.SigEventCallback(C.onTerm), nil)
+ ev_int.Add(salticidae.SIGINT)
+ ev_term := salticidae.NewSigEvent(ec, salticidae.SigEventCallback(C.onTerm), nil)
+ ev_term.Add(salticidae.SIGTERM)
+
+ ec.Dispatch()
+ alice.net.Stop()
+ bob.net.Stop()
+ C.free(unsafe.Pointer(alice.cname))
+ C.free(unsafe.Pointer(bob.cname))
+}
diff --git a/test_p2p_stress/main.go b/test_p2p_stress/main.go
index 9e0757f..69f9d6c 100644
--- a/test_p2p_stress/main.go
+++ b/test_p2p_stress/main.go
@@ -240,6 +240,7 @@ func onTerm(_ C.int, _ unsafe.Pointer) {
func main() {
ec = salticidae.NewEventContext()
+ err := salticidae.NewError()
var addrs []salticidae.NetAddr
for i := 0; i < 5; i++ {
@@ -256,22 +257,23 @@ func main() {
ids = make([](*C.int), len(addrs))
for i, addr := range addrs {
ec := salticidae.NewEventContext()
+ net := salticidae.NewPeerNetwork(ec, netconfig, &err); checkError(&err)
apps[i] = AppContext {
addr: addr,
ec: ec,
- net: salticidae.NewPeerNetwork(ec, netconfig),
+ net: net,
tcall: salticidae.NewThreadCall(ec),
tc: make(map[uint64] *TestContext),
}
ids[i] = (*C.int)(C.malloc(C.sizeof_int))
*ids[i] = C.int(i)
_i := unsafe.Pointer(ids[i])
- net := apps[i].net.AsMsgNetwork()
- net.RegHandler(MSG_OPCODE_RAND, salticidae.MsgNetworkMsgCallback(C.onReceiveRand), _i)
- net.RegHandler(MSG_OPCODE_ACK, salticidae.MsgNetworkMsgCallback(C.onReceiveAck), _i)
- net.RegConnHandler(salticidae.MsgNetworkConnCallback(C.connHandler), _i)
- net.RegErrorHandler(salticidae.MsgNetworkErrorCallback(C.errorHandler), _i)
- net.Start()
+ mnet := net.AsMsgNetwork()
+ mnet.RegHandler(MSG_OPCODE_RAND, salticidae.MsgNetworkMsgCallback(C.onReceiveRand), _i)
+ mnet.RegHandler(MSG_OPCODE_ACK, salticidae.MsgNetworkMsgCallback(C.onReceiveAck), _i)
+ mnet.RegConnHandler(salticidae.MsgNetworkConnCallback(C.connHandler), _i)
+ mnet.RegErrorHandler(salticidae.MsgNetworkErrorCallback(C.errorHandler), _i)
+ mnet.Start()
}
threads.Add(len(apps))
@@ -280,7 +282,7 @@ func main() {
go func() {
err := salticidae.NewError()
a := &apps[app_id]
- a.net.Listen(a.addr, &err)
+ a.net.Listen(a.addr, &err); checkError(&err)
for _, addr := range addrs {
if !addr.IsEq(a.addr) {
a.net.AddPeer(addr)