|
- // +build !windows
-
- package capstan
-
- import (
- "encoding/json"
- "fmt"
- "net"
- "os"
- "os/signal"
-
- syscall "golang.org/x/sys/unix"
- )
-
- func InitNetwork() (err error, errc chan error, close chan struct{}) {
- var env *fdenv
-
- fds = newfdmap()
- errc = make(chan error, 1)
- close = make(chan struct{}, 1)
-
- enc := os.Getenv("CAPSTAN_SOCKETS")
- if enc != "" {
- err = json.Unmarshal([]byte(enc), &env)
- if err != nil {
- // Do error.
- }
-
- parentPID = env.ParentPID
- for _, socket := range env.Sockets {
- fds.addDescriptor(socket.Name, socket.FD)
- }
-
- for k, v := range env.Addrs {
- fds.addAddrMap(k, v)
- }
-
- if parentPID != 0 {
- if err = syscall.Kill(parentPID, syscall.SIGUSR1); err != nil {
- return
- }
- // TODO: We should check the state of the parent process to ensure
- // it actually has terminated.
- parentPID = 0
- }
- }
-
- go func() {
- hup := make(chan os.Signal, 1)
- signal.Notify(hup, syscall.SIGHUP)
-
- usr1 := make(chan os.Signal, 1)
- signal.Notify(usr1, syscall.SIGUSR1)
-
- interrupt := make(chan os.Signal, 1)
- signal.Notify(interrupt, os.Interrupt)
- signal.Notify(interrupt, syscall.SIGTERM)
-
- // TODO: Replace fragile signalling infrastructure with pipes.
- for {
- select {
- case <-hup:
- go func() {
- if err := prelaunchFunc(); err != nil {
- errc <- err
- return
- }
- err := Relaunch()
- if err != nil {
- errc <- err
- }
- }()
- if err != nil {
- errc <- err
- }
- case <-usr1:
- if parentPID == 0 {
- close <- struct{}{}
- } else {
- parentPID = 0
- }
- case <-interrupt:
- for name, listener := range fds.sockets {
- if _, ok := listener.(*net.UnixListener); ok {
- stat, err := os.Stat(name)
- if os.IsNotExist(err) {
- continue
- }
- if stat.Mode()&os.ModeSocket == os.ModeSocket {
- os.Remove(name)
- }
- }
- }
- close <- struct{}{}
- }
- }
- }()
-
- return
- }
-
- func Listen(network, addr string) (net.Listener, error) {
- if fd, ok := fds.getDescriptor(network, addr); ok {
- listener, err := resumeListener(network, addr, fd)
- if err != nil {
- return nil, err
- }
- if _, ok := listener.(Listener); ok {
- fds.addListener(listener.(Listener), network, addr)
- return listener, nil
- }
- }
-
- listener, err := net.Listen(network, addr)
- if err != nil {
- return nil, err
- }
-
- if network == "unix" {
- ln, _ := listener.(*net.UnixListener)
- ln.SetUnlinkOnClose(false)
- }
-
- if _, ok := listener.(Listener); !ok {
- return nil, fmt.Errorf("listener does not implement the appropriate interface")
- }
-
- if err := fds.addListener(listener.(Listener), network, addr); err != nil {
- return nil, err
- }
- return listener, nil
- }
-
- func StopListening(listener net.Listener) error {
- fds.removeListener(listener)
- return listener.Close()
- }
|