github.com/containers/podman/v4@v4.9.4/pkg/machine/sockets.go (about)

     1  package machine
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"net"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/containers/podman/v4/pkg/machine/define"
    12  )
    13  
    14  // SetSocket creates a new machine file for the socket and assigns it to
    15  // `socketLoc`
    16  func SetSocket(socketLoc *define.VMFile, path string, symlink *string) error {
    17  	socket, err := define.NewMachineFile(path, symlink)
    18  	if err != nil {
    19  		return err
    20  	}
    21  	*socketLoc = *socket
    22  	return nil
    23  }
    24  
    25  // ReadySocketPath returns the filepath for the ready socket
    26  func ReadySocketPath(runtimeDir, machineName string) string {
    27  	return filepath.Join(runtimeDir, fmt.Sprintf("%s_ready.sock", machineName))
    28  }
    29  
    30  // ListenAndWaitOnSocket waits for a new connection to the listener and sends
    31  // any error back through the channel. ListenAndWaitOnSocket is intended to be
    32  // used as a goroutine
    33  func ListenAndWaitOnSocket(errChan chan<- error, listener net.Listener) {
    34  	conn, err := listener.Accept()
    35  	if err != nil {
    36  		errChan <- err
    37  		return
    38  	}
    39  	_, err = bufio.NewReader(conn).ReadString('\n')
    40  
    41  	if closeErr := conn.Close(); closeErr != nil {
    42  		errChan <- closeErr
    43  		return
    44  	}
    45  
    46  	errChan <- err
    47  }
    48  
    49  // DialSocketWithBackoffs attempts to connect to the socket in maxBackoffs attempts
    50  func DialSocketWithBackoffs(maxBackoffs int, backoff time.Duration, socketPath string) (conn net.Conn, err error) {
    51  	for i := 0; i < maxBackoffs; i++ {
    52  		if i > 0 {
    53  			time.Sleep(backoff)
    54  			backoff *= 2
    55  		}
    56  		conn, err = net.Dial("unix", socketPath)
    57  		if err == nil {
    58  			return conn, nil
    59  		}
    60  	}
    61  	return nil, err
    62  }
    63  
    64  // DialSocketWithBackoffsAndProcCheck attempts to connect to the socket in
    65  // maxBackoffs attempts. After every failure to connect, it makes sure the
    66  // specified process is alive
    67  func DialSocketWithBackoffsAndProcCheck(
    68  	maxBackoffs int,
    69  	backoff time.Duration,
    70  	socketPath string,
    71  	checkProccessStatus func(string, int, *bytes.Buffer) error,
    72  	procHint string,
    73  	procPid int,
    74  	errBuf *bytes.Buffer,
    75  ) (conn net.Conn, err error) {
    76  	for i := 0; i < maxBackoffs; i++ {
    77  		if i > 0 {
    78  			time.Sleep(backoff)
    79  			backoff *= 2
    80  		}
    81  		conn, err = net.Dial("unix", socketPath)
    82  		if err == nil {
    83  			return conn, nil
    84  		}
    85  
    86  		// check to make sure process denoted by procHint is alive
    87  		err = checkProccessStatus(procHint, procPid, errBuf)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  	}
    92  	return nil, err
    93  }