mirror of
https://github.com/pion/stun.git
synced 2025-10-19 06:04:33 +08:00
{client,agent}: don't alloc on client.Do
This commit is contained in:
81
README.md
81
README.md
@@ -73,46 +73,47 @@ goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/gortc/stun
|
||||
PASS
|
||||
benchmark iter time/iter throughput bytes alloc allocs
|
||||
--------- ---- --------- ---------- ----------- ------
|
||||
BenchmarkMappedAddress_AddTo-12 100000000 22.50 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkAlternateServer_AddTo-12 100000000 22.20 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkAgent_GC-12 1000000 2038.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkAgent_Process-12 30000000 47.60 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_GetNotFound-12 300000000 4.29 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkClient_Do-12 2000000 534.00 ns/op 16 B/op 1 allocs/op
|
||||
BenchmarkErrorCode_AddTo-12 30000000 42.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkErrorCodeAttribute_AddTo-12 50000000 30.90 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkErrorCodeAttribute_GetFrom-12 200000000 7.78 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkFingerprint_AddTo-12 30000000 47.30 ns/op 931.09 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkFingerprint_Check-12 50000000 38.20 ns/op 1360.04 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkBuildOverhead/Build-12 10000000 139.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBuildOverhead/BuildNonPointer-12 5000000 249.00 ns/op 100 B/op 4 allocs/op
|
||||
BenchmarkBuildOverhead/Raw-12 20000000 114.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessageIntegrity_AddTo-12 2000000 1022.00 ns/op 19.56 MB/s 480 B/op 6 allocs/op
|
||||
BenchmarkMessageIntegrity_Check-12 1000000 1084.00 ns/op 29.50 MB/s 480 B/op 6 allocs/op
|
||||
BenchmarkMessage_Write-12 100000000 16.10 ns/op 1743.03 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkMessageType_Value-12 2000000000 0.23 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_WriteTo-12 200000000 8.11 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_ReadFrom-12 100000000 18.30 ns/op 1095.75 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_ReadBytes-12 100000000 10.70 ns/op 1870.83 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkIsMessage-12 2000000000 0.68 ns/op 29576.35 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_NewTransactionID-12 3000000 393.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessageFull-12 10000000 138.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessageFullHardcore-12 30000000 53.90 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_WriteHeader-12 300000000 5.45 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkUsername_AddTo-12 100000000 15.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkUsername_GetFrom-12 100000000 11.90 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkNonce_AddTo-12 100000000 20.70 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkNonce_AddTo_BadLength-12 100000000 27.40 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkNonce_GetFrom-12 200000000 11.90 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkUnknownAttributes/AddTo-12 100000000 18.90 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkUnknownAttributes/GetFrom-12 100000000 13.70 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkXOR-12 100000000 14.60 ns/op 70066.01 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkXORSafe-12 20000000 98.80 ns/op 10363.12 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkXORFast-12 100000000 13.80 ns/op 74327.93 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkXORMappedAddress_AddTo-12 50000000 35.20 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkXORMappedAddress_GetFrom-12 100000000 22.30 ns/op 0 B/op 0 allocs/op
|
||||
benchmark iter time/iter throughput bytes alloc allocs
|
||||
--------- ---- --------- ---------- ----------- ------
|
||||
BenchmarkMappedAddress_AddTo-12 1000000000 22.90 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkAlternateServer_AddTo-12 1000000000 23.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkAgent_GC-12 10000000 2217.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkAgent_Process-12 300000000 52.80 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_GetNotFound-12 3000000000 4.13 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkClient_Do-12 30000000 495.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkErrorCode_AddTo-12 300000000 41.10 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkErrorCodeAttribute_AddTo-12 500000000 30.90 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkErrorCodeAttribute_GetFrom-12 2000000000 7.84 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkFingerprint_AddTo-12 300000000 46.60 ns/op 944.52 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkFingerprint_Check-12 500000000 37.20 ns/op 1397.50 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkBuildOverhead/Build-12 100000000 133.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBuildOverhead/BuildNonPointer-12 100000000 262.00 ns/op 100 B/op 4 allocs/op
|
||||
BenchmarkBuildOverhead/Raw-12 100000000 119.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessageIntegrity_AddTo-12 20000000 1058.00 ns/op 18.89 MB/s 480 B/op 6 allocs/op
|
||||
BenchmarkMessageIntegrity_Check-12 20000000 1023.00 ns/op 31.27 MB/s 480 B/op 6 allocs/op
|
||||
BenchmarkMessage_Write-12 1000000000 16.10 ns/op 1734.19 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkMessageType_Value-12 10000000000 0.23 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_WriteTo-12 2000000000 8.19 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_ReadFrom-12 1000000000 18.00 ns/op 1108.32 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_ReadBytes-12 2000000000 10.50 ns/op 1896.39 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkIsMessage-12 10000000000 0.64 ns/op 31241.13 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_NewTransactionID-12 50000000 385.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessageFull-12 100000000 134.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessageFullHardcore-12 300000000 52.70 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMessage_WriteHeader-12 3000000000 5.21 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkUsername_AddTo-12 1000000000 14.60 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkUsername_GetFrom-12 2000000000 11.70 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkNonce_AddTo-12 1000000000 20.00 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkNonce_AddTo_BadLength-12 300000000 49.40 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkNonce_GetFrom-12 2000000000 11.80 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkUnknownAttributes/AddTo-12 1000000000 18.50 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkUnknownAttributes/GetFrom-12 1000000000 13.40 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkXOR-12 1000000000 14.00 ns/op 73071.52 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkXORSafe-12 100000000 102.00 ns/op 9945.44 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkXORFast-12 1000000000 13.60 ns/op 75332.68 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkXORMappedAddress_AddTo-12 500000000 35.20 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkXORMappedAddress_GetFrom-12 1000000000 22.30 ns/op 0 B/op 0 allocs/op
|
||||
ok github.com/gortc/stun 698.712s
|
||||
```
|
||||
|
||||
# development
|
||||
|
55
agent.go
55
agent.go
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
// AgentOptions are required to initialize Agent.
|
||||
type AgentOptions struct {
|
||||
Handler AgentFn // Default handler, can be nil.
|
||||
Handler Handler // Default handler, can be nil.
|
||||
}
|
||||
|
||||
// NewAgent initializes and returns new Agent from options.
|
||||
@@ -32,17 +32,28 @@ type Agent struct {
|
||||
transactions map[transactionID]agentTransaction
|
||||
closed bool // all calls are invalid if true
|
||||
mux sync.Mutex // protects transactions and closed
|
||||
zeroHandler AgentFn // handles non-registered transactions if set
|
||||
zeroHandler Handler // handles non-registered transactions if set
|
||||
}
|
||||
|
||||
// AgentFn is called on transaction state change.
|
||||
// Usage of e is valid only during call, user must
|
||||
// copy needed fields explicitly.
|
||||
type AgentFn func(e AgentEvent)
|
||||
// Handler handles state changes of transaction.
|
||||
type Handler interface {
|
||||
// HandleEvent is called on transaction state change.
|
||||
// Usage of e is valid only during call, user must
|
||||
// copy needed fields explicitly.
|
||||
HandleEvent(e Event)
|
||||
}
|
||||
|
||||
// AgentEvent is set of arguments passed to AgentFn, describing
|
||||
// HandlerFunc is function that implements Handler interface.
|
||||
type HandlerFunc func(e Event)
|
||||
|
||||
// HandleEvent implements Handler.
|
||||
func (f HandlerFunc) HandleEvent(e Event) {
|
||||
f(e)
|
||||
}
|
||||
|
||||
// Event is set of arguments passed to AgentFn, describing
|
||||
// an transaction event. Do not reuse outside AgentFn.
|
||||
type AgentEvent struct {
|
||||
type Event struct {
|
||||
Message *Message
|
||||
Error error
|
||||
}
|
||||
@@ -54,7 +65,7 @@ type AgentEvent struct {
|
||||
type agentTransaction struct {
|
||||
id transactionID
|
||||
deadline time.Time
|
||||
f AgentFn
|
||||
h Handler
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -81,7 +92,7 @@ func (a *Agent) StopWithError(id [TransactionIDSize]byte, err error) error {
|
||||
if !exists {
|
||||
return ErrTransactionNotExists
|
||||
}
|
||||
t.f(AgentEvent{
|
||||
t.h.HandleEvent(Event{
|
||||
Error: err,
|
||||
})
|
||||
return nil
|
||||
@@ -101,7 +112,7 @@ var ErrAgentClosed = errors.New("agent is closed")
|
||||
// Could return ErrAgentClosed, ErrTransactionExists.
|
||||
// Callback f is guaranteed to be eventually called. See AgentFn for
|
||||
// callback processing constraints.
|
||||
func (a *Agent) Start(id [TransactionIDSize]byte, deadline time.Time, f AgentFn) error {
|
||||
func (a *Agent) Start(id [TransactionIDSize]byte, deadline time.Time, h Handler) error {
|
||||
a.mux.Lock()
|
||||
defer a.mux.Unlock()
|
||||
if a.closed {
|
||||
@@ -113,7 +124,7 @@ func (a *Agent) Start(id [TransactionIDSize]byte, deadline time.Time, f AgentFn)
|
||||
}
|
||||
a.transactions[id] = agentTransaction{
|
||||
id: id,
|
||||
f: f,
|
||||
h: h,
|
||||
deadline: deadline,
|
||||
}
|
||||
return nil
|
||||
@@ -132,7 +143,7 @@ var ErrTransactionTimeOut = errors.New("transaction is timed out")
|
||||
//
|
||||
// It is safe to call Collect concurrently but makes no sense.
|
||||
func (a *Agent) Collect(gcTime time.Time) error {
|
||||
toCall := make([]AgentFn, 0, agentCollectCap)
|
||||
toCall := make([]Handler, 0, agentCollectCap)
|
||||
toRemove := make([]transactionID, 0, agentCollectCap)
|
||||
a.mux.Lock()
|
||||
if a.closed {
|
||||
@@ -149,7 +160,7 @@ func (a *Agent) Collect(gcTime time.Time) error {
|
||||
for id, t := range a.transactions {
|
||||
if t.deadline.Before(gcTime) {
|
||||
toRemove = append(toRemove, id)
|
||||
toCall = append(toCall, t.f)
|
||||
toCall = append(toCall, t.h)
|
||||
}
|
||||
}
|
||||
// Un-registering timed out transactions.
|
||||
@@ -161,11 +172,11 @@ func (a *Agent) Collect(gcTime time.Time) error {
|
||||
a.mux.Unlock()
|
||||
// Sending ErrTransactionTimeOut to all callbacks, blocking
|
||||
// Collect until last one.
|
||||
event := AgentEvent{
|
||||
event := Event{
|
||||
Error: ErrTransactionTimeOut,
|
||||
}
|
||||
for _, f := range toCall {
|
||||
f(event)
|
||||
for _, handler := range toCall {
|
||||
handler.HandleEvent(event)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -175,7 +186,7 @@ func (a *Agent) Collect(gcTime time.Time) error {
|
||||
// handle is not provided, message is silently ignored.
|
||||
// Call blocks until handler returns.
|
||||
func (a *Agent) Process(m *Message) error {
|
||||
e := AgentEvent{
|
||||
e := Event{
|
||||
Message: m,
|
||||
}
|
||||
a.mux.Lock()
|
||||
@@ -187,9 +198,9 @@ func (a *Agent) Process(m *Message) error {
|
||||
delete(a.transactions, m.TransactionID)
|
||||
a.mux.Unlock()
|
||||
if ok {
|
||||
t.f(e)
|
||||
t.h.HandleEvent(e)
|
||||
} else if a.zeroHandler != nil {
|
||||
a.zeroHandler(e)
|
||||
a.zeroHandler.HandleEvent(e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -197,7 +208,7 @@ func (a *Agent) Process(m *Message) error {
|
||||
// Close terminates all transactions with ErrAgentClosed and renders Agent to
|
||||
// closed state.
|
||||
func (a *Agent) Close() error {
|
||||
e := AgentEvent{
|
||||
e := Event{
|
||||
Error: ErrAgentClosed,
|
||||
}
|
||||
a.mux.Lock()
|
||||
@@ -206,7 +217,7 @@ func (a *Agent) Close() error {
|
||||
return ErrAgentClosed
|
||||
}
|
||||
for _, t := range a.transactions {
|
||||
t.f(e)
|
||||
t.h.HandleEvent(e)
|
||||
}
|
||||
a.transactions = nil
|
||||
a.closed = true
|
||||
|
@@ -8,22 +8,21 @@ import (
|
||||
func TestAgent_ProcessInTransaction(t *testing.T) {
|
||||
m := New()
|
||||
a := NewAgent(AgentOptions{
|
||||
Handler: func(e AgentEvent) {
|
||||
Handler: HandlerFunc(func(e Event) {
|
||||
t.Error("should not be called")
|
||||
},
|
||||
}),
|
||||
})
|
||||
if err := m.NewTransactionID(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := a.Start(m.TransactionID, time.Time{}, func(e AgentEvent) {
|
||||
if err := a.Start(m.TransactionID, time.Time{}, HandlerFunc(func(e Event) {
|
||||
if e.Error != nil {
|
||||
t.Errorf("got error: %s", e.Error)
|
||||
}
|
||||
if !e.Message.Equal(m) {
|
||||
t.Errorf("%s (got) != %s (expected)", e.Message, m)
|
||||
}
|
||||
|
||||
}); err != nil {
|
||||
})); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := a.Process(m); err != nil {
|
||||
@@ -37,14 +36,14 @@ func TestAgent_ProcessInTransaction(t *testing.T) {
|
||||
func TestAgent_Process(t *testing.T) {
|
||||
m := New()
|
||||
a := NewAgent(AgentOptions{
|
||||
Handler: func(e AgentEvent) {
|
||||
Handler: HandlerFunc(func(e Event) {
|
||||
if e.Error != nil {
|
||||
t.Errorf("got error: %s", e.Error)
|
||||
}
|
||||
if !e.Message.Equal(m) {
|
||||
t.Errorf("%s (got) != %s (expected)", e.Message, m)
|
||||
}
|
||||
},
|
||||
}),
|
||||
})
|
||||
if err := m.NewTransactionID(); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -91,11 +90,11 @@ func TestAgent_Stop(t *testing.T) {
|
||||
t.Fatalf("unexpected error: %s, should be %s", err, ErrTransactionNotExists)
|
||||
}
|
||||
id := NewTransactionID()
|
||||
called := make(chan AgentEvent, 1)
|
||||
called := make(chan Event, 1)
|
||||
timeout := time.Millisecond * 200
|
||||
if err := a.Start(id, time.Now().Add(timeout), func(e AgentEvent) {
|
||||
if err := a.Start(id, time.Now().Add(timeout), HandlerFunc(func(e Event) {
|
||||
called <- e
|
||||
}); err != nil {
|
||||
})); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := a.Stop(id); err != nil {
|
||||
@@ -119,18 +118,18 @@ func TestAgent_Stop(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var noopHandler = func(e AgentEvent) {}
|
||||
var noopHandler HandlerFunc = func(e Event) {}
|
||||
|
||||
func TestAgent_GC(t *testing.T) {
|
||||
a := NewAgent(AgentOptions{
|
||||
Handler: noopHandler,
|
||||
})
|
||||
shouldTimeOut := func(e AgentEvent) {
|
||||
var shouldTimeOut HandlerFunc = func(e Event) {
|
||||
if e.Error != ErrTransactionTimeOut {
|
||||
t.Errorf("should time out, but got <%s>", e.Error)
|
||||
}
|
||||
}
|
||||
shouldNotTimeOut := func(e AgentEvent) {
|
||||
var shouldNotTimeOut HandlerFunc = func(e Event) {
|
||||
if e.Error == ErrTransactionTimeOut {
|
||||
t.Error("should not time out")
|
||||
}
|
||||
|
78
client.go
78
client.go
@@ -65,7 +65,7 @@ type Connection interface {
|
||||
type ClientAgent interface {
|
||||
Process(*Message) error
|
||||
Close() error
|
||||
Start(id [TransactionIDSize]byte, deadline time.Time, f AgentFn) error
|
||||
Start(id [TransactionIDSize]byte, deadline time.Time, f Handler) error
|
||||
Stop(id [TransactionIDSize]byte) error
|
||||
Collect(time.Time) error
|
||||
}
|
||||
@@ -184,21 +184,14 @@ func (c *Client) Indicate(m *Message) error {
|
||||
return c.Start(m, time.Time{}, nil)
|
||||
}
|
||||
|
||||
type clientCallState struct {
|
||||
callback func(event AgentEvent)
|
||||
// callbackWaitHandler blocks on wait() call until callback is called.
|
||||
type callbackWaitHandler struct {
|
||||
callback func(event Event)
|
||||
cond *sync.Cond
|
||||
processed bool
|
||||
}
|
||||
|
||||
func (s *clientCallState) wait() {
|
||||
s.cond.L.Lock()
|
||||
for !s.processed {
|
||||
s.cond.Wait()
|
||||
}
|
||||
s.cond.L.Unlock()
|
||||
}
|
||||
|
||||
func (s *clientCallState) wrapper(e AgentEvent) {
|
||||
func (s *callbackWaitHandler) HandleEvent(e Event) {
|
||||
if s.callback == nil {
|
||||
panic("s.callback is nil")
|
||||
}
|
||||
@@ -209,66 +202,73 @@ func (s *clientCallState) wrapper(e AgentEvent) {
|
||||
s.cond.L.Unlock()
|
||||
}
|
||||
|
||||
func (s *clientCallState) setCallback(f func(event AgentEvent)) {
|
||||
func (s *callbackWaitHandler) wait() {
|
||||
s.cond.L.Lock()
|
||||
for !s.processed {
|
||||
s.cond.Wait()
|
||||
}
|
||||
s.cond.L.Unlock()
|
||||
}
|
||||
|
||||
func (s *callbackWaitHandler) setCallback(f func(event Event)) {
|
||||
if f == nil {
|
||||
panic("f is nil")
|
||||
}
|
||||
s.callback = f
|
||||
}
|
||||
|
||||
func (s *clientCallState) reset() {
|
||||
func (s *callbackWaitHandler) reset() {
|
||||
s.processed = false
|
||||
s.callback = nil
|
||||
}
|
||||
|
||||
func newClientCallState(f func(event AgentEvent)) *clientCallState {
|
||||
return &clientCallState{
|
||||
cond: sync.NewCond(new(sync.Mutex)),
|
||||
callback: f,
|
||||
}
|
||||
}
|
||||
|
||||
var clientCallStatePool = sync.Pool{
|
||||
var callbackWaitHandlerPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return newClientCallState(nil)
|
||||
return &callbackWaitHandler{
|
||||
cond: sync.NewCond(new(sync.Mutex)),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Do is Start wrapper that waits until callback is called. If no callback
|
||||
// provided, Indicate is called instead.
|
||||
//
|
||||
// Do has memory allocation overhead due to blocking, see BenchmarkClient_Do.
|
||||
// Use Start for zero overhead.
|
||||
func (c *Client) Do(m *Message, d time.Time, f func(AgentEvent)) error {
|
||||
// Do has cpu overhead due to blocking, see BenchmarkClient_Do.
|
||||
// Use Start method for less overhead.
|
||||
func (c *Client) Do(m *Message, d time.Time, f func(Event)) error {
|
||||
if f == nil {
|
||||
return c.Indicate(m)
|
||||
}
|
||||
state := clientCallStatePool.Get().(*clientCallState)
|
||||
state.setCallback(f)
|
||||
err := c.Start(m, d, state.wrapper)
|
||||
state.wait()
|
||||
state.reset()
|
||||
clientCallStatePool.Put(state)
|
||||
return err
|
||||
h := callbackWaitHandlerPool.Get().(*callbackWaitHandler)
|
||||
h.setCallback(f)
|
||||
defer func() {
|
||||
h.reset()
|
||||
callbackWaitHandlerPool.Put(h)
|
||||
}()
|
||||
if err := c.Start(m, d, h); err != nil {
|
||||
return err
|
||||
}
|
||||
h.wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start starts transaction (if f set) and writes message to server, callback
|
||||
// Start starts transaction (if f set) and writes message to server, handler
|
||||
// is called asynchronously.
|
||||
func (c *Client) Start(m *Message, d time.Time, f func(AgentEvent)) error {
|
||||
func (c *Client) Start(m *Message, d time.Time, h Handler) error {
|
||||
c.closedMux.RLock()
|
||||
closed := c.closed
|
||||
c.closedMux.RUnlock()
|
||||
if closed {
|
||||
return ErrClientClosed
|
||||
}
|
||||
if f != nil {
|
||||
// Starting transaction only if f is set. Useful for indications.
|
||||
if err := c.a.Start(m.TransactionID, d, f); err != nil {
|
||||
if h != nil {
|
||||
// Starting transaction only if h is set. Useful for indications.
|
||||
if err := c.a.Start(m.TransactionID, d, h); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := m.WriteTo(c.c)
|
||||
if err != nil && f != nil {
|
||||
if err != nil && h != nil {
|
||||
// Stopping transaction instead of waiting until deadline.
|
||||
if stopErr := c.a.Stop(m.TransactionID); stopErr != nil {
|
||||
return StopErr{
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
type TestAgent struct {
|
||||
f chan AgentFn
|
||||
f chan Handler
|
||||
}
|
||||
|
||||
func (n *TestAgent) Close() error {
|
||||
@@ -20,7 +20,7 @@ func (TestAgent) Collect(time.Time) error { return nil }
|
||||
|
||||
func (TestAgent) Process(m *Message) error { return nil }
|
||||
|
||||
func (n *TestAgent) Start(id [TransactionIDSize]byte, deadline time.Time, f AgentFn) error {
|
||||
func (n *TestAgent) Start(id [TransactionIDSize]byte, deadline time.Time, f Handler) error {
|
||||
n.f <- f
|
||||
return nil
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (noopConnection) Close() error {
|
||||
func BenchmarkClient_Do(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
agent := &TestAgent{
|
||||
f: make(chan AgentFn, 1000),
|
||||
f: make(chan Handler, 1000),
|
||||
}
|
||||
client := NewClient(ClientOptions{
|
||||
Agent: agent,
|
||||
@@ -55,17 +55,17 @@ func BenchmarkClient_Do(b *testing.B) {
|
||||
})
|
||||
defer client.Close()
|
||||
go func() {
|
||||
e := AgentEvent{
|
||||
e := Event{
|
||||
Error: nil,
|
||||
Message: nil,
|
||||
}
|
||||
for f := range agent.f {
|
||||
f(e)
|
||||
f.HandleEvent(e)
|
||||
}
|
||||
}()
|
||||
m := new(Message)
|
||||
m.Encode()
|
||||
noopF := func(event AgentEvent) {
|
||||
noopF := func(event Event) {
|
||||
// pass
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -140,7 +140,7 @@ func TestClient_Do(t *testing.T) {
|
||||
m.TransactionID = response.TransactionID
|
||||
m.Encode()
|
||||
d := time.Now().Add(time.Second)
|
||||
if err := c.Do(m, d, func(event AgentEvent) {
|
||||
if err := c.Do(m, d, func(event Event) {
|
||||
if event.Error != nil {
|
||||
t.Error(event.Error)
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ func main() {
|
||||
log.Fatal("dial:", err)
|
||||
}
|
||||
deadline := time.Now().Add(time.Second * 5)
|
||||
if err := c.Do(stun.MustBuild(stun.TransactionID, stun.BindingRequest), deadline, func(res stun.AgentEvent) {
|
||||
if err := c.Do(stun.MustBuild(stun.TransactionID, stun.BindingRequest), deadline, func(res stun.Event) {
|
||||
if res.Error != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ func main() {
|
||||
}
|
||||
timeout := time.Second
|
||||
deadline := time.Now().Add(timeout)
|
||||
if err := client.Do(request, deadline, func(event stun.AgentEvent) {
|
||||
if err := client.Do(request, deadline, func(event stun.Event) {
|
||||
if event.Error != nil {
|
||||
log.Fatalln("got event with error:", event.Error)
|
||||
}
|
||||
|
Reference in New Issue
Block a user