Skip to content

Commit 65db12c

Browse files
committed
1 parent 9af113d commit 65db12c

File tree

2 files changed

+260
-30
lines changed

2 files changed

+260
-30
lines changed

pkg/signaler/signaler.go

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
11
package signaler
22

33
import (
4+
"crypto/hmac"
5+
"crypto/sha1"
6+
"encoding/base64"
47
"encoding/json"
8+
"fmt"
59
"net"
610
"net/http"
11+
"net/url"
712
"strings"
8-
9-
"github.com/gorilla/mux"
13+
"time"
1014

1115
"github.com/cloudwebrtc/flutter-webrtc-server/pkg/logger"
1216
"github.com/cloudwebrtc/flutter-webrtc-server/pkg/turn"
17+
"github.com/cloudwebrtc/flutter-webrtc-server/pkg/util"
1318
"github.com/cloudwebrtc/flutter-webrtc-server/pkg/websocket"
1419
)
1520

21+
const (
22+
sharedKey = `flutter-webrtc-turn-server-shared-key`
23+
)
24+
25+
type TurnCredentials struct {
26+
Username string `json:"username"`
27+
Password string `json:"password"`
28+
TTL int `json:"ttl"`
29+
Uris []string `json:"uris"`
30+
}
31+
1632
func Marshal(m map[string]interface{}) string {
1733
if byt, err := json.Marshal(m); err != nil {
1834
logger.Errorf(err.Error())
@@ -52,26 +68,33 @@ type Session struct {
5268
}
5369

5470
type Signaler struct {
55-
peers map[string]Peer
56-
sessions map[string]Session
57-
turn *turn.TurnServer
71+
peers map[string]Peer
72+
sessions map[string]Session
73+
turn *turn.TurnServer
74+
expresMap *util.ExpiredMap
5875
}
5976

6077
func NewSignaler(turn *turn.TurnServer) *Signaler {
6178
var signaler = &Signaler{
62-
peers: make(map[string]Peer),
63-
sessions: make(map[string]Session),
64-
turn: turn,
79+
peers: make(map[string]Peer),
80+
sessions: make(map[string]Session),
81+
turn: turn,
82+
expresMap: util.NewExpiredMap(),
6583
}
6684
signaler.turn.AuthHandler = signaler.authHandler
6785
return signaler
6886
}
6987

7088
func (s Signaler) authHandler(username string, realm string, srcAddr net.Addr) ([]byte, bool) {
71-
// handle turn auth info.
89+
// handle turn credential.
90+
if found, info := s.expresMap.Get(username); found {
91+
credential := info.(TurnCredentials)
92+
return []byte(credential.Password), true
93+
}
7294
return nil, false
7395
}
7496

97+
// NotifyPeersUpdate .
7598
func (s *Signaler) NotifyPeersUpdate(conn *websocket.WebSocketConn, peers map[string]Peer) {
7699
infos := []PeerInfo{}
77100
for _, peer := range peers {
@@ -85,35 +108,58 @@ func (s *Signaler) NotifyPeersUpdate(conn *websocket.WebSocketConn, peers map[st
85108
}
86109
}
87110

88-
// HandleTurnServerCredentials
111+
// HandleTurnServerCredentials .
89112
// https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
90113
func (s *Signaler) HandleTurnServerCredentials(writer http.ResponseWriter, request *http.Request) {
91114
writer.Header().Set("Content-Type", "application/json")
92-
params := mux.Vars(request) //Get params
93-
service := params["service"]
115+
116+
params, err := url.ParseQuery(request.URL.RawQuery)
117+
if err != nil {
118+
119+
}
120+
logger.Debugf("%v", params)
121+
service := params["service"][0]
94122
if service != "turn" {
95123
return
96124
}
125+
username := params["username"][0]
126+
timestamp := time.Now().Unix()
127+
turnUsername := fmt.Sprintf("%d:%s", timestamp, username)
128+
hmac := hmac.New(sha1.New, []byte(sharedKey))
129+
hmac.Write([]byte(turnUsername))
130+
turnPassword := base64.StdEncoding.EncodeToString(hmac.Sum(nil))
97131
/*
98-
username := params["username"]
99-
100-
//key := params["key"]
101-
timestamp := time.Now().Unix()
102-
turnUserName := string(timestamp) + ":" + username
103-
// credential = base64(hmac(key, turn_username))
104-
credential := ""
105-
106-
{
107-
"username" : "12334939:mbzrxpgjys",
108-
"password" : "adfsaflsjfldssia",
109-
"ttl" : 86400,
110-
"uris" : [
111-
"turn:1.2.3.4:9991?transport=udp",
112-
]
113-
}
132+
{
133+
"username" : "12334939:mbzrxpgjys",
134+
"password" : "adfsaflsjfldssia",
135+
"ttl" : 86400,
136+
"uris" : [
137+
"turn:1.2.3.4:9991?transport=udp",
138+
"turn:1.2.3.4:9992?transport=tcp",
139+
"turns:1.2.3.4:443?transport=tcp"
140+
]
141+
}
142+
For client pc.
143+
var iceServer = {
144+
"username": response.username,
145+
"credential": response.password,
146+
"uris": response.uris
147+
};
148+
var config = {"iceServers": [iceServer]};
149+
var pc = new RTCPeerConnection(config);
150+
114151
*/
115-
//tuts := make(map[string]interface{})
116-
json.NewEncoder(writer).Encode(params)
152+
ttl := 86400
153+
credential := TurnCredentials{
154+
Username: turnUsername,
155+
Password: turnPassword,
156+
TTL: ttl,
157+
Uris: []string{
158+
"turn:1.2.3.4:19302?transport=udp",
159+
},
160+
}
161+
s.expresMap.Set(turnUsername, credential, int64(ttl))
162+
json.NewEncoder(writer).Encode(credential)
117163
}
118164

119165
func (s *Signaler) HandleNewWebSocket(conn *websocket.WebSocketConn, request *http.Request) {

pkg/util/expire.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package util
2+
3+
import (
4+
"sync"
5+
"sync/atomic"
6+
"time"
7+
8+
"github.com/cloudwebrtc/flutter-webrtc-server/pkg/logger"
9+
)
10+
11+
type val struct {
12+
data interface{}
13+
expiredTime int64
14+
}
15+
16+
const delChannelCap = 100
17+
18+
type ExpiredMap struct {
19+
m map[interface{}]*val
20+
timeMap map[int64][]interface{}
21+
lck *sync.Mutex
22+
stop chan struct{}
23+
needStop int32
24+
}
25+
26+
func NewExpiredMap() *ExpiredMap {
27+
e := ExpiredMap{
28+
m: make(map[interface{}]*val),
29+
lck: new(sync.Mutex),
30+
timeMap: make(map[int64][]interface{}),
31+
stop: make(chan struct{}),
32+
}
33+
atomic.StoreInt32(&e.needStop, 0)
34+
go e.run(time.Now().Unix())
35+
return &e
36+
}
37+
38+
type delMsg struct {
39+
keys []interface{}
40+
t int64
41+
}
42+
43+
func (e *ExpiredMap) run(now int64) {
44+
t := time.NewTicker(time.Second * 1)
45+
delCh := make(chan *delMsg, delChannelCap)
46+
go func() {
47+
for v := range delCh {
48+
if atomic.LoadInt32(&e.needStop) == 1 {
49+
logger.Infof("---del stop---")
50+
return
51+
}
52+
e.multiDelete(v.keys, v.t)
53+
}
54+
}()
55+
for {
56+
select {
57+
case <-t.C:
58+
now++
59+
if keys, found := e.timeMap[now]; found {
60+
delCh <- &delMsg{keys: keys, t: now}
61+
}
62+
case <-e.stop:
63+
logger.Infof("=== STOP ===")
64+
atomic.StoreInt32(&e.needStop, 1)
65+
delCh <- &delMsg{keys: []interface{}{}, t: 0}
66+
return
67+
}
68+
}
69+
}
70+
71+
func (e *ExpiredMap) Set(key, value interface{}, expireSeconds int64) {
72+
if expireSeconds <= 0 {
73+
return
74+
}
75+
logger.Debugf("ExpiredMap: Set %s ttl[%d] => %v", key, expireSeconds, value)
76+
e.lck.Lock()
77+
defer e.lck.Unlock()
78+
expiredTime := time.Now().Unix() + expireSeconds
79+
e.m[key] = &val{
80+
data: value,
81+
expiredTime: expiredTime,
82+
}
83+
e.timeMap[expiredTime] = append(e.timeMap[expiredTime], key)
84+
}
85+
86+
func (e *ExpiredMap) Get(key interface{}) (found bool, value interface{}) {
87+
e.lck.Lock()
88+
defer e.lck.Unlock()
89+
if found = e.checkDeleteKey(key); !found {
90+
return
91+
}
92+
value = e.m[key].data
93+
return
94+
}
95+
96+
func (e *ExpiredMap) Delete(key interface{}) {
97+
e.lck.Lock()
98+
delete(e.m, key)
99+
e.lck.Unlock()
100+
}
101+
102+
func (e *ExpiredMap) Remove(key interface{}) {
103+
e.Delete(key)
104+
}
105+
106+
func (e *ExpiredMap) multiDelete(keys []interface{}, t int64) {
107+
e.lck.Lock()
108+
defer e.lck.Unlock()
109+
delete(e.timeMap, t)
110+
for _, key := range keys {
111+
delete(e.m, key)
112+
}
113+
}
114+
115+
func (e *ExpiredMap) Length() int {
116+
e.lck.Lock()
117+
defer e.lck.Unlock()
118+
return len(e.m)
119+
}
120+
121+
func (e *ExpiredMap) Size() int {
122+
return e.Length()
123+
}
124+
125+
func (e *ExpiredMap) TTL(key interface{}) int64 {
126+
e.lck.Lock()
127+
defer e.lck.Unlock()
128+
if !e.checkDeleteKey(key) {
129+
return -1
130+
}
131+
return e.m[key].expiredTime - time.Now().Unix()
132+
}
133+
134+
func (e *ExpiredMap) Clear() {
135+
e.lck.Lock()
136+
defer e.lck.Unlock()
137+
e.m = make(map[interface{}]*val)
138+
e.timeMap = make(map[int64][]interface{})
139+
}
140+
141+
func (e *ExpiredMap) Close() {
142+
e.lck.Lock()
143+
defer e.lck.Unlock()
144+
e.stop <- struct{}{}
145+
}
146+
147+
func (e *ExpiredMap) Stop() {
148+
e.Close()
149+
}
150+
151+
func (e *ExpiredMap) DoForEach(handler func(interface{}, interface{})) {
152+
e.lck.Lock()
153+
defer e.lck.Unlock()
154+
for k, v := range e.m {
155+
if !e.checkDeleteKey(k) {
156+
continue
157+
}
158+
handler(k, v)
159+
}
160+
}
161+
162+
func (e *ExpiredMap) DoForEachWithBreak(handler func(interface{}, interface{}) bool) {
163+
e.lck.Lock()
164+
defer e.lck.Unlock()
165+
for k, v := range e.m {
166+
if !e.checkDeleteKey(k) {
167+
continue
168+
}
169+
if handler(k, v) {
170+
break
171+
}
172+
}
173+
}
174+
175+
func (e *ExpiredMap) checkDeleteKey(key interface{}) bool {
176+
if val, found := e.m[key]; found {
177+
if val.expiredTime <= time.Now().Unix() {
178+
delete(e.m, key)
179+
return false
180+
}
181+
return true
182+
}
183+
return false
184+
}

0 commit comments

Comments
 (0)