| 
					
				 | 
			
			
				@@ -5,45 +5,149 @@ import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"net" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"os" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"syscall" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"time" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"v2ray.com/core/common/bitmask" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type Listener struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	ln           net.Listener 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	listenerChan <-chan net.Conn 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	listenerChan chan<- net.Conn 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	ctx          context.Context 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	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) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	vln := &Listener{path: path} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vln := &Listener{path: path, state: STATE_INITIALIZED, ctx: ctx} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return vln, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (ls *Listener) Down() error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	err := ls.ln.Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		newError(err).AtDebug().WriteToLog() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var err error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if !ls.state.Has(STATE_LOWERUP | STATE_UP) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		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 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	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 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		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.Name = ls.path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	addr.Net = "unix" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	li, err := net.ListenUnix("unix", addr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ls.ln = li 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		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 { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -51,7 +155,7 @@ func isUnixDomainSocketFileSystemBased(path string) bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return path[0] != 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func AcquireLock(lockfilepath string) (*os.File, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func acquireLock(lockfilepath string) (*os.File, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	f, err := os.Create(lockfilepath) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		newError(err).AtDebug().WriteToLog() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -69,6 +173,37 @@ func AcquireLock(lockfilepath string) (*os.File, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		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 
			 |