@ -6,7 +6,9 @@ package ipnserver
import (
import (
"bufio"
"bufio"
"bytes"
"context"
"context"
"encoding/json"
"errors"
"errors"
"fmt"
"fmt"
"io"
"io"
@ -251,8 +253,7 @@ func (s *server) serveConn(ctx context.Context, c net.Conn, logf logger.Logf) {
return
return
}
}
defer c . Close ( )
defer c . Close ( )
serverToClient := func ( b [ ] byte ) { ipn . WriteMsg ( c , b ) }
bs := ipn . NewBackendServer ( logf , nil , jsonNotifier ( c , s . logf ) )
bs := ipn . NewBackendServer ( logf , nil , serverToClient )
_ , occupied := err . ( inUseOtherUserError )
_ , occupied := err . ( inUseOtherUserError )
if occupied {
if occupied {
bs . SendInUseOtherUserErrorMessage ( err . Error ( ) )
bs . SendInUseOtherUserErrorMessage ( err . Error ( ) )
@ -567,7 +568,9 @@ func (s *server) setServerModeUserLocked() {
}
}
}
}
func ( s * server ) writeToClients ( b [ ] byte ) {
var jsonEscapedZero = [ ] byte ( ` \u0000 ` )
func ( s * server ) writeToClients ( n ipn . Notify ) {
inServerMode := s . b . InServerMode ( )
inServerMode := s . b . InServerMode ( )
s . mu . Lock ( )
s . mu . Lock ( )
@ -584,9 +587,18 @@ func (s *server) writeToClients(b []byte) {
}
}
}
}
if len ( s . clients ) == 0 {
// Common case (at least on busy servers): nobody
// connected (no GUI, etc), so return before
// serializing JSON.
return
}
if b , ok := marshalNotify ( n , s . logf ) ; ok {
for c := range s . clients {
for c := range s . clients {
ipn . WriteMsg ( c , b )
ipn . WriteMsg ( c , b )
}
}
}
}
}
// Run runs a Tailscale backend service.
// Run runs a Tailscale backend service.
@ -671,8 +683,7 @@ func Run(ctx context.Context, logf logger.Logf, logid string, getEngine func() (
errMsg := err . Error ( )
errMsg := err . Error ( )
go func ( ) {
go func ( ) {
defer c . Close ( )
defer c . Close ( )
serverToClient := func ( b [ ] byte ) { ipn . WriteMsg ( c , b ) }
bs := ipn . NewBackendServer ( logf , nil , jsonNotifier ( c , logf ) )
bs := ipn . NewBackendServer ( logf , nil , serverToClient )
bs . SendErrorMessage ( errMsg )
bs . SendErrorMessage ( errMsg )
time . Sleep ( time . Second )
time . Sleep ( time . Second )
} ( )
} ( )
@ -962,3 +973,25 @@ func peerPid(entries []netstat.Entry, la, ra netaddr.IPPort) int {
}
}
return 0
return 0
}
}
// jsonNotifier returns a notify-writer func that writes ipn.Notify
// messages to w.
func jsonNotifier ( w io . Writer , logf logger . Logf ) func ( ipn . Notify ) {
return func ( n ipn . Notify ) {
if b , ok := marshalNotify ( n , logf ) ; ok {
ipn . WriteMsg ( w , b )
}
}
}
func marshalNotify ( n ipn . Notify , logf logger . Logf ) ( b [ ] byte , ok bool ) {
b , err := json . Marshal ( n )
if err != nil {
logf ( "ipnserver: [unexpected] error serializing JSON: %v" , err )
return nil , false
}
if bytes . Contains ( b , jsonEscapedZero ) {
logf ( "[unexpected] zero byte in BackendServer.send notify message: %q" , b )
}
return b , true
}