github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/hypervisor/rpcd/connectToVmSerialPort.go (about)

     1  package rpcd
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/Cloud-Foundations/Dominator/lib/errors"
     7  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
     8  	"github.com/Cloud-Foundations/Dominator/proto/hypervisor"
     9  )
    10  
    11  func (t *srpcType) ConnectToVmSerialPort(conn *srpc.Conn) error {
    12  	var request hypervisor.ConnectToVmSerialPortRequest
    13  	if err := conn.Decode(&request); err != nil {
    14  		return err
    15  	}
    16  	closeNotifier := make(chan error, 1)
    17  	input, output, err := t.manager.ConnectToVmSerialPort(request.IpAddress,
    18  		conn.GetAuthInformation(), request.PortNumber)
    19  	if input != nil {
    20  		defer close(input)
    21  	}
    22  	e := conn.Encode(hypervisor.ConnectToVmSerialPortResponse{
    23  		Error: errors.ErrorToString(err)})
    24  	if e != nil {
    25  		return e
    26  	}
    27  	if e := conn.Flush(); e != nil {
    28  		return e
    29  	}
    30  	if err != nil {
    31  		return err
    32  	}
    33  	go func() { // Read from connection and write to input until EOF.
    34  		buffer := make([]byte, 256)
    35  		for {
    36  			if nRead, err := conn.Read(buffer); err != nil {
    37  				if err != io.EOF {
    38  					closeNotifier <- err
    39  				} else {
    40  					closeNotifier <- srpc.ErrorCloseClient
    41  				}
    42  				return
    43  			} else {
    44  				for _, char := range buffer[:nRead] {
    45  					input <- char
    46  				}
    47  			}
    48  		}
    49  	}()
    50  	// Read from output until closure or transmission error.
    51  	for {
    52  		select {
    53  		case data, ok := <-output:
    54  			var buffer []byte
    55  			if !ok {
    56  				buffer = []byte("VM serial port closed\n")
    57  			} else {
    58  				buffer = readData(data, output)
    59  			}
    60  			if _, err := conn.Write(buffer); err != nil {
    61  				return err
    62  			}
    63  			if err := conn.Flush(); err != nil {
    64  				return err
    65  			}
    66  			if !ok {
    67  				return srpc.ErrorCloseClient
    68  			}
    69  		case err := <-closeNotifier:
    70  			return err
    71  		}
    72  	}
    73  }
    74  
    75  func readData(firstByte byte, moreBytes <-chan byte) []byte {
    76  	buffer := make([]byte, 1, len(moreBytes)+1)
    77  	buffer[0] = firstByte
    78  	for {
    79  		select {
    80  		case char, ok := <-moreBytes:
    81  			if !ok {
    82  				return buffer
    83  			}
    84  			buffer = append(buffer, char)
    85  		default:
    86  			return buffer
    87  		}
    88  	}
    89  }