1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-28 02:05:23 +00:00

finish transport listener

This commit is contained in:
Shelikhoo 2018-03-18 21:46:50 +08:00
parent 8e5063dedf
commit 3b1f0ae300
No known key found for this signature in database
GPG Key ID: 7791BDB0709ABD21

View File

@ -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 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 {
@ -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