/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/libkb/loopback.go
238 строк
6 KB
chrisnojima
build(mobile): harden gobuild.sh and go bind pipeline 2 (#29364)
08 июл 2026, 15:25
Не верифицирован
08 июл 2026, 15:25
19b55b3
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package libkb import ( "bytes" "io" "net" "sync" "syscall" "time" ) // LoopbackAddr is an address class that implement the net.Addr interface for loopback // devices type LoopbackAddr struct{} // LoopbackListener is a listener that creates new loopback connections. // It is goroutine safe. type LoopbackListener struct { logCtx LogContext // Protects closing of ch so that we can close ch // and set isClosed atomically. mutex sync.Mutex ch chan *LoopbackConn isClosed bool } // LoopbackConn implments the net.Conn interface but is used to loopback // from a process to itself. It is goroutine safe. type LoopbackConn struct { // wMutex protects isClosed and ch to protect against // double-closes, and writes after close. It protects the // writer, hence the 'w'. wMutex sync.Mutex isClosed bool ch chan<- []byte // rMutex Protects partnerCh and buf, to ensure that only // one Go routine is reading at a time. It protects the // reader hence the 'r' rMutex sync.Mutex partnerCh <-chan []byte buf bytes.Buffer } // NewLoopbackListener creates a new Loopback listener func NewLoopbackListener(ctx LogContext) *LoopbackListener { return &LoopbackListener{ logCtx: ctx, ch: make(chan *LoopbackConn), isClosed: false, } } // NewLoopbackConnPair makes a new loopback connection pair func NewLoopbackConnPair() (*LoopbackConn, *LoopbackConn) { aCh := make(chan []byte) bCh := make(chan []byte) a := &LoopbackConn{ch: aCh} b := &LoopbackConn{ch: bCh} a.partnerCh = bCh b.partnerCh = aCh return a, b } // LoopbackDial dials the given LoopbackListener and yields an new net.Conn // that's a connection to it. func (ll *LoopbackListener) Dial() (net.Conn, error) { ll.logCtx.GetLog().Debug("+ LoopbackListener.Dial") ll.mutex.Lock() defer ll.mutex.Unlock() if ll.isClosed { return nil, syscall.EINVAL } a, b := NewLoopbackConnPair() ll.ch <- a return b, nil } // Accept waits for and returns the next connection to the listener. func (ll *LoopbackListener) Accept() (ret net.Conn, err error) { ll.logCtx.GetLog().Debug("+ LoopbackListener.Accept") var ok bool // We can't hold the lock (even if we had to) since that would // deadlock the process (to have the Accepter and Dialer contending // the same lock). if ret, ok = <-ll.ch; !ok { err = syscall.EINVAL } ll.logCtx.GetLog().Debug("- LoopbackListener.Accept -> %v", err) return ret, err } // Close closes the listener. // Any blocked Accept operations will be unblocked and return errors func (ll *LoopbackListener) Close() (err error) { ll.mutex.Lock() defer ll.mutex.Unlock() if ll.isClosed { ll.logCtx.GetLog().Debug("LoopbackListener.Close: already closed") return syscall.EINVAL } ll.logCtx.GetLog().Debug("LoopbackListener.Close: closing") ll.isClosed = true close(ll.ch) return } // Addr returns the listener's network address. func (ll *LoopbackListener) Addr() (addr net.Addr) { return LoopbackAddr{} } // Read reads data from the connection. func (lc *LoopbackConn) Read(b []byte) (n int, err error) { lc.rMutex.Lock() defer lc.rMutex.Unlock() if lc.buf.Len() > 0 { return lc.buf.Read(b) } msg, ok := <-lc.partnerCh if !ok { return 0, io.EOF } // Copy directly from message to caller's buffer, only buffering leftovers. // Most messages fit in the read buffer, so this saves one full copy. n = copy(b, msg) if n < len(msg) { lc.buf.Write(msg[n:]) } return n, nil } // TryRead is a non-blocking Read: it returns immediately with n == 0 when no // data is pending. Used by the mobile bridge to coalesce already-pending // writes into one delivery, amortizing the per-call native->JS bridge hop. func (lc *LoopbackConn) TryRead(b []byte) (n int, err error) { lc.rMutex.Lock() defer lc.rMutex.Unlock() if lc.buf.Len() > 0 { return lc.buf.Read(b) } select { case msg, ok := <-lc.partnerCh: if !ok { return 0, io.EOF } n = copy(b, msg) if n < len(msg) { lc.buf.Write(msg[n:]) } return n, nil default: return 0, nil } } // Write writes data to the connection. func (lc *LoopbackConn) Write(b []byte) (n int, err error) { lc.wMutex.Lock() defer lc.wMutex.Unlock() if lc.isClosed { return 0, syscall.EINVAL } lc.ch <- b return len(b), nil } // Close closes the connection. // Any blocked Read or Write operations will be unblocked and return errors. func (lc *LoopbackConn) Close() (err error) { lc.wMutex.Lock() defer lc.wMutex.Unlock() if lc.isClosed { return syscall.EINVAL } lc.isClosed = true close(lc.ch) return nil } // LocalAddr returns the local network address. func (lc *LoopbackConn) LocalAddr() (addr net.Addr) { return } // RemoteAddr returns the remote network address. func (lc *LoopbackConn) RemoteAddr() (addr net.Addr) { return } // SetDeadline sets the read and write deadlines associated // with the connection. It is equivalent to calling both // SetReadDeadline and SetWriteDeadline. // // A deadline is an absolute time after which I/O operations // fail with a timeout (see type Error) instead of // blocking. The deadline applies to all future I/O, not just // the immediately following call to Read or Write. // // An idle timeout can be implemented by repeatedly extending // the deadline after successful Read or Write calls. // // A zero value for t means I/O operations will not time out. func (lc *LoopbackConn) SetDeadline(t time.Time) (err error) { return } // SetReadDeadline sets the deadline for future Read calls. // A zero value for t means Read will not time out. func (lc *LoopbackConn) SetReadDeadline(t time.Time) (err error) { return } // SetWriteDeadline sets the deadline for future Write calls. // Even if write times out, it may return n > 0, indicating that // some of the data was successfully written. // A zero value for t means Write will not time out. func (lc *LoopbackConn) SetWriteDeadline(t time.Time) (err error) { return } // Network returns the name of the network func (la LoopbackAddr) Network() (s string) { return "loopback" } // String returns the string form of address func (la LoopbackAddr) String() (s string) { return "0" }