mirror of https://github.com/v2ray/v2ray-core
finish transport listener
parent
8e5063dedf
commit
3b1f0ae300
|
@ -5,45 +5,149 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"v2ray.com/core/common/bitmask"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Listener struct {
|
type Listener struct {
|
||||||
ln net.Listener
|
ln net.Listener
|
||||||
listenerChan <-chan net.Conn
|
listenerChan chan<- net.Conn
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
path string
|
path string
|
||||||
lockfile os.File
|
lockfile *os.File
|
||||||
|
state bitmask.Byte
|
||||||
|
cancal func()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
STATE_UNDEFINED = 0
|
||||||
|
STATE_INITIALIZED = 1 << iota
|
||||||
|
STATE_LOWERUP = 1 << iota
|
||||||
|
STATE_UP = 1 << iota
|
||||||
|
STATE_TAINT = 1 << iota
|
||||||
|
)
|
||||||
|
|
||||||
func ListenDS(ctx context.Context, path string) (*Listener, error) {
|
func ListenDS(ctx context.Context, path string) (*Listener, error) {
|
||||||
|
|
||||||
vln := &Listener{path: path}
|
vln := &Listener{path: path, state: STATE_INITIALIZED, ctx: ctx}
|
||||||
return vln, nil
|
return vln, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *Listener) Down() error {
|
func (ls *Listener) Down() error {
|
||||||
err := ls.ln.Close()
|
var err error
|
||||||
if err != nil {
|
if !ls.state.Has(STATE_LOWERUP | STATE_UP) {
|
||||||
newError(err).AtDebug().WriteToLog()
|
err = newError(ls.state).Base(newError("Invalid State:Down"))
|
||||||
|
if ___DEBUG_PANIC_WHEN_ENCOUNTED_IMPOSSIBLE_ERROR {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ls.cancal()
|
||||||
|
closeerr := ls.ln.Close()
|
||||||
|
var lockerr error
|
||||||
|
if isUnixDomainSocketFileSystemBased(ls.path) {
|
||||||
|
lockerr = giveupLock(ls.lockfile)
|
||||||
|
}
|
||||||
|
if closeerr != nil && lockerr != nil {
|
||||||
|
if ___DEBUG_PANIC_WHEN_ERROR_UNPROPAGATEABLE {
|
||||||
|
panic(closeerr.Error() + lockerr.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if closeerr != nil {
|
||||||
|
return newError("Cannot Close Unix domain socket listener").Base(closeerr)
|
||||||
|
}
|
||||||
|
if lockerr != nil {
|
||||||
|
return newError("Cannot release lock for Unix domain socket listener").Base(lockerr)
|
||||||
|
}
|
||||||
|
ls.state.Clear(STATE_LOWERUP | STATE_UP)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Setup systen level Listener
|
//LowerUP Setup systen level Listener
|
||||||
func (ls *Listener) LowerUP() error {
|
func (ls *Listener) LowerUP() error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if !ls.state.Has(STATE_INITIALIZED) || ls.state.Has(STATE_LOWERUP) {
|
||||||
|
err = newError(ls.state).Base(newError("Invalid State:LowerUP"))
|
||||||
|
if ___DEBUG_PANIC_WHEN_ENCOUNTED_IMPOSSIBLE_ERROR {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if isUnixDomainSocketFileSystemBased(ls.path) && !___DEBUG_IGNORE_FLOCK {
|
if isUnixDomainSocketFileSystemBased(ls.path) && !___DEBUG_IGNORE_FLOCK {
|
||||||
|
ls.lockfile, err = acquireLock(ls.path + ".lock")
|
||||||
|
if err != nil {
|
||||||
|
newError(err).AtDebug().WriteToLog()
|
||||||
|
return newError("Unable to acquire lock for filesystem based unix domain socket").Base(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cleansePath(ls.path)
|
||||||
|
if err != nil {
|
||||||
|
return newError("Unable to cleanse path for the creation of unix domain socket").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := new(net.UnixAddr)
|
addr := new(net.UnixAddr)
|
||||||
addr.Name = ls.path
|
addr.Name = ls.path
|
||||||
addr.Net = "unix"
|
addr.Net = "unix"
|
||||||
li, err := net.ListenUnix("unix", addr)
|
li, err := net.ListenUnix("unix", addr)
|
||||||
|
ls.ln = li
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return newError("Unable to listen unix domain socket").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ls.state.Set(STATE_LOWERUP)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *Listener) UP(listener chan<- net.Conn, allowkick bool) error {
|
||||||
|
var err error
|
||||||
|
if !ls.state.Has(STATE_INITIALIZED|STATE_LOWERUP) || (ls.state.Has(STATE_UP) && !allowkick) {
|
||||||
|
err = newError(ls.state).Base(newError("Invalid State:UP"))
|
||||||
|
if ___DEBUG_PANIC_WHEN_ENCOUNTED_IMPOSSIBLE_ERROR {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ls.listenerChan = listener
|
||||||
|
if ls.state.Has(STATE_UP) {
|
||||||
|
cctx, cancel := context.WithCancel(ls.ctx)
|
||||||
|
ls.cancal = cancel
|
||||||
|
go ls.uploop(cctx)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *Listener) uploop(cctx context.Context) {
|
||||||
|
var lasterror error
|
||||||
|
errortolerance := 5
|
||||||
|
for {
|
||||||
|
if cctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, err := ls.ln.Accept()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
newError("Cannot Accept socket from listener").Base(err).AtDebug().WriteToLog()
|
||||||
|
if err == lasterror {
|
||||||
|
errortolerance--
|
||||||
|
if errortolerance == 0 {
|
||||||
|
newError("unix domain socket melt down as the error is repeating").Base(err).AtError().WriteToLog()
|
||||||
|
ls.cancal()
|
||||||
|
}
|
||||||
|
newError("unix domain socket listener is throttling accept as the error is repeating").Base(err).AtError().WriteToLog()
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
}
|
||||||
|
lasterror = err
|
||||||
|
}
|
||||||
|
|
||||||
|
ls.listenerChan <- conn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUnixDomainSocketFileSystemBased(path string) bool {
|
func isUnixDomainSocketFileSystemBased(path string) bool {
|
||||||
|
@ -51,7 +155,7 @@ func isUnixDomainSocketFileSystemBased(path string) bool {
|
||||||
return path[0] != 0
|
return path[0] != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func AcquireLock(lockfilepath string) (*os.File, error) {
|
func acquireLock(lockfilepath string) (*os.File, error) {
|
||||||
f, err := os.Create(lockfilepath)
|
f, err := os.Create(lockfilepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
newError(err).AtDebug().WriteToLog()
|
newError(err).AtDebug().WriteToLog()
|
||||||
|
@ -69,6 +173,37 @@ func AcquireLock(lockfilepath string) (*os.File, error) {
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func giveupLock(locker *os.File) error {
|
||||||
|
err := syscall.Flock(int(locker.Fd()), syscall.LOCK_UN)
|
||||||
|
if err != nil {
|
||||||
|
closeerr := locker.Close()
|
||||||
|
if err != nil {
|
||||||
|
if ___DEBUG_PANIC_WHEN_ERROR_UNPROPAGATEABLE {
|
||||||
|
panic(closeerr)
|
||||||
|
}
|
||||||
|
newError(closeerr).AtDebug().WriteToLog()
|
||||||
|
}
|
||||||
|
newError(err).AtDebug().WriteToLog()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
closeerr := locker.Close()
|
||||||
|
if closeerr != nil {
|
||||||
|
newError(closeerr).AtDebug().WriteToLog()
|
||||||
|
return closeerr
|
||||||
|
}
|
||||||
|
return closeerr
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleansePath(path string) error {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == os.ErrNotExist {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = os.Remove(path)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//DEBUG CONSTS
|
//DEBUG CONSTS
|
||||||
|
|
Loading…
Reference in New Issue