Files
server/ws/room.go
T
Jannis Mattheis d71c303df7 Use IPv4 stun for IPv6 connections
* User1 connects with IPv6
* User2 connects with IPv4 (without any support for IPv6)
* User1 asks via STUN for his address, and receives a IPv6 address back
* User2 asks via STUN for his address, and receives a IPv4 address back
* User2 cannot connect to User1 IPv6 address

After this fix: User1 asks both for his IPv4 and IPv6 addresses.

See #56
2020-12-03 19:49:31 +00:00

147 lines
3.5 KiB
Go

package ws
import (
"fmt"
"net"
"sort"
"github.com/rs/xid"
"github.com/screego/server/config"
"github.com/screego/server/util"
"github.com/screego/server/ws/outgoing"
)
type ConnectionMode string
const (
ConnectionLocal ConnectionMode = "local"
ConnectionSTUN ConnectionMode = "stun"
ConnectionTURN ConnectionMode = config.AuthModeTurn
)
type Room struct {
ID string
CloseOnOwnerLeave bool
Mode ConnectionMode
Users map[xid.ID]*User
Sessions map[xid.ID]*RoomSession
}
const (
CloseOwnerLeft = "Owner Left"
CloseDone = "Read End"
)
func (r *Room) newSession(host, client xid.ID, rooms *Rooms) {
id := xid.New()
r.Sessions[id] = &RoomSession{
Host: host,
Client: client,
}
sessionCreatedTotal.Inc()
iceHost := []outgoing.ICEServer{}
iceClient := []outgoing.ICEServer{}
switch r.Mode {
case ConnectionLocal:
case ConnectionSTUN:
iceHost = []outgoing.ICEServer{{URLs: rooms.addresses("stun", false)}}
iceClient = []outgoing.ICEServer{{URLs: rooms.addresses("stun", false)}}
case ConnectionTURN:
hostPW := util.RandString(20)
clientPW := util.RandString(20)
hostName := id.String() + "host"
rooms.turnServer.Allow(hostName, hostPW, r.Users[host].Addr)
clientName := id.String() + "client"
rooms.turnServer.Allow(clientName, clientPW, r.Users[client].Addr)
iceHost = []outgoing.ICEServer{{
URLs: rooms.addresses("turn", true),
Credential: hostPW,
Username: hostName,
}}
iceClient = []outgoing.ICEServer{{
URLs: rooms.addresses("turn", true),
Credential: clientPW,
Username: clientName,
}}
}
r.Users[host].Write <- outgoing.HostSession{Peer: client, ID: id, ICEServers: iceHost}
r.Users[client].Write <- outgoing.ClientSession{Peer: host, ID: id, ICEServers: iceClient}
}
func (r *Rooms) addresses(prefix string, tcp bool) (result []string) {
if r.config.ExternalIPV4 != nil {
result = append(result, fmt.Sprintf("%s:%s:%s", prefix, r.config.ExternalIPV4.String(), r.turnServer.Port))
if tcp {
result = append(result, fmt.Sprintf("%s:%s:%s?transport=tcp", prefix, r.config.ExternalIPV4.String(), r.turnServer.Port))
}
}
if r.config.ExternalIPV6 != nil {
result = append(result, fmt.Sprintf("%s:[%s]:%s", prefix, r.config.ExternalIPV6.String(), r.turnServer.Port))
if tcp {
result = append(result, fmt.Sprintf("%s:[%s]:%s?transport=tcp", prefix, r.config.ExternalIPV6.String(), r.turnServer.Port))
}
}
return
}
func (r *Room) closeSession(rooms *Rooms, id xid.ID) {
if r.Mode == ConnectionTURN {
rooms.turnServer.Disallow(id.String() + "host")
rooms.turnServer.Disallow(id.String() + "client")
}
delete(r.Sessions, id)
sessionClosedTotal.Inc()
}
type RoomSession struct {
Host xid.ID
Client xid.ID
}
func (r *Room) notifyInfoChanged() {
for _, current := range r.Users {
users := []outgoing.User{}
for _, user := range r.Users {
users = append(users, outgoing.User{
ID: user.ID,
Name: user.Name,
Streaming: user.Streaming,
You: current == user,
Owner: user.Owner,
})
}
sort.Slice(users, func(i, j int) bool {
left := users[i]
right := users[j]
if left.Owner != right.Owner {
return left.Owner
}
if left.Streaming != right.Streaming {
return left.Streaming
}
return left.Name < right.Name
})
current.Write <- outgoing.Room{
ID: r.ID,
Users: users,
}
}
}
type User struct {
ID xid.ID
Addr net.IP
Name string
Streaming bool
Owner bool
Write chan<- outgoing.Message
Close chan<- string
}