1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4// +build windows 5 6package libkb 7 8import ( 9 "errors" 10 "net" 11 "path/filepath" 12 "strings" 13 "time" 14 15 "github.com/keybase/client/go/logger" 16 mspipe "github.com/keybase/go-winio" 17) 18 19func NewSocket(g *GlobalContext) (ret Socket, err error) { 20 var s string 21 s, err = g.Env.GetSocketBindFile() 22 if err != nil { 23 return 24 } 25 if len(s) == 0 { 26 err = errors.New("Empty SocketFile, can't make pipe") 27 return 28 } 29 s = `\\.\pipe\kbservice` + strings.TrimPrefix(s, filepath.VolumeName(s)) 30 log := g.Log 31 if log == nil { 32 log = logger.NewNull() 33 } 34 35 // ownership tests fail when server is in same proces, as in tests 36 return SocketInfo{ 37 log: log, 38 bindFile: s, 39 dialFiles: []string{s}, 40 testOwner: g.Env.Test == nil, 41 }, nil 42} 43 44func NewSocketWithFiles( 45 log logger.Logger, bindFile string, _ []string) Socket { 46 s := `\\.\pipe\kbservice` + 47 strings.TrimPrefix(bindFile, filepath.VolumeName(bindFile)) 48 return SocketInfo{ 49 log: log, 50 bindFile: s, 51 dialFiles: []string{s}, 52 } 53} 54 55func (s SocketInfo) BindToSocket() (ret net.Listener, err error) { 56 s.log.Info("Binding to pipe:%s", s.bindFile) 57 return mspipe.ListenPipe(s.bindFile, nil) 58} 59 60func (s SocketInfo) DialSocket() (ret net.Conn, err error) { 61 timeout := time.Duration(1) * time.Second 62 pipe, err := mspipe.DialPipe(s.dialFiles[0], &timeout) 63 if err != nil { 64 // Be sure to return a nil interface, and not a nil npipe.PipeConn 65 // See https://keybase.atlassian.net/browse/CORE-2675 for when this 66 // bit us. 67 return nil, err 68 } 69 // This can't happen right now, but in the future it might, so protect against ourselves 70 // so we don't get vexing (*foo)(nil)/interface{}(nil) bugs. 71 if pipe == nil { 72 return nil, errors.New("bad npipe result; nil npipe.PipeConn but no error") 73 } 74 75 // Test ownership 76 if s.testOwner { 77 owner, err := IsPipeowner(s.log, s.dialFiles[0]) 78 if err != nil { 79 return nil, err 80 } 81 if !owner.IsOwner { 82 return nil, errors.New("failed to verify pipe ownership") 83 } 84 } 85 // Success case 86 return pipe, err 87} 88 89func IsSocketClosedError(e error) bool { 90 return e == mspipe.ErrPipeListenerClosed 91} 92