-
Notifications
You must be signed in to change notification settings - Fork 6
/
session_state.go
120 lines (101 loc) · 3.07 KB
/
session_state.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package secureio
import (
"context"
"sync/atomic"
)
// SessionState is the state of a Session. It describes
// what's going on right now with the Session.
type SessionState uint64
const (
// SessionStateNew means the Session was just created and even
// did not Start it's routines.
SessionStateNew = SessionState(iota)
// SessionStateClosed means the session is already deattached from
// the backend io.ReadWriteCloser, closed and cannot be used anymore.
SessionStateClosed
// SessionStateKeyExchanging is the state which follows after
// SessionStateNew. It means the Session started it's routines
// (including the key exchanger routine), but not yet successfully
// exchanged with keys (at least once).
SessionStateKeyExchanging
// SessionStateNegotiating is the state which follows after
// SessionStateKeyExchanging. It means the Session is performing
// experiments to find the optimal settings for further
// communications.
SessionStateNegotiating
// SessionStateEstablished means the Session successfully exchanged
// with keys and currently operational.
SessionStateEstablished
// SessionStatePaused means the Session was temporary detached from
// the backend io.ReadWriteCloser by method `(*Session).SetPause`.
SessionStatePaused
// SessionStateClosing is a transition state to SessionStateClosed
SessionStateClosing
)
type sessionStateStorage struct {
SessionState
changeChan chan struct{}
changeChanLocker lockerRWMutex
}
func newSessionStateStorage() *sessionStateStorage {
return &sessionStateStorage{
SessionState: SessionStateNew,
changeChan: make(chan struct{}),
}
}
func (state SessionState) String() string {
switch state {
case SessionStateNew:
return `new`
case SessionStateClosed:
return `closed`
case SessionStateKeyExchanging:
return `key_exchanging`
case SessionStateNegotiating:
return `negotiating`
case SessionStateEstablished:
return `established`
case SessionStatePaused:
return `paused`
case SessionStateClosing:
return `closing`
}
return `unknown`
}
func (stateStor *sessionStateStorage) WaitFor(ctx context.Context, states ...SessionState) SessionState {
for {
var changeChan chan struct{}
stateStor.changeChanLocker.RLockDo(func() {
changeChan = stateStor.changeChan
})
loadedState := stateStor.Load()
for i := 0; i < len(states); i++ {
if loadedState == states[i] {
return loadedState
}
}
select {
case <-ctx.Done():
return loadedState
case <-changeChan:
}
}
}
// Load atomically returns the currents state
func (state *SessionState) Load() SessionState {
return SessionState(atomic.LoadUint64((*uint64)(state)))
}
func (stateStor *sessionStateStorage) Set(newState SessionState, cancelOnStates ...SessionState) (oldState SessionState) {
stateStor.changeChanLocker.LockDo(func() {
oldState = stateStor.Load()
for i := 0; i < len(cancelOnStates); i++ {
if oldState == cancelOnStates[i] {
return
}
}
atomic.StoreUint64((*uint64)(&stateStor.SessionState), uint64(newState))
close(stateStor.changeChan)
stateStor.changeChan = make(chan struct{})
})
return
}