github.com/openebs/api@v1.12.0/pkg/util/unixsock.go (about)

     1  // Copyright © 2020 The OpenEBS Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package util
    16  
    17  import (
    18  	"io"
    19  	"net"
    20  	"strings"
    21  
    22  	"k8s.io/klog"
    23  )
    24  
    25  // IstgtUctlUnxpath is the storage path for the UNIX domain socket from istgt
    26  const (
    27  	IstgtUctlUnxpath = "/var/run/istgt_ctl_sock"
    28  	EndOfLine        = "\r\n"
    29  	IstgtHeader      = "iSCSI Target Controller version"
    30  )
    31  
    32  //IsResponseEOD will detect if the data coming from UNIX pipe is completely received
    33  func IsResponseEOD(resp []string, cmd string) bool {
    34  	return (len(resp) != 0 && !strings.HasPrefix(resp[len(resp)-1], IstgtHeader) &&
    35  		!strings.HasPrefix(resp[len(resp)-1], cmd))
    36  }
    37  
    38  //Reader reads the response from unix domain socket
    39  func Reader(r io.Reader, cmd string) []string {
    40  	resp := []string{}
    41  	//collect bytes into fulllines buffer till the end of line character is reached
    42  	fulllines := []byte{}
    43  	for {
    44  		buf := make([]byte, 1024)
    45  		n, err := r.Read(buf[:])
    46  		if n > 0 {
    47  			klog.Infof("Client got: %s", string(buf[0:n]))
    48  			fulllines = append(fulllines, buf[0:n]...)
    49  			if strings.HasSuffix(string(fulllines), EndOfLine) {
    50  				lines := strings.Split(string(fulllines), EndOfLine)
    51  				for _, line := range lines {
    52  					if len(line) != 0 {
    53  						klog.Infof("Appending line to resp: %s", line)
    54  						resp = append(resp, line+EndOfLine)
    55  					}
    56  				}
    57  				//clear the fulllines buffer once the response lines are appended to the response
    58  				fulllines = nil
    59  			}
    60  			if IsResponseEOD(resp, cmd) {
    61  				klog.Infof("Breaking out of loop for line: %s", resp[len(resp)-1])
    62  				break
    63  			}
    64  		}
    65  		if err != nil {
    66  			klog.Errorf("Read error : %v", err)
    67  			break
    68  		}
    69  		buf = nil
    70  	}
    71  	klog.Infof("response : %v", resp)
    72  	return resp
    73  }
    74  
    75  //Writer writes a command to unix domain socket
    76  func Writer(w io.Writer, msg string) error {
    77  	_, err := w.Write([]byte(msg))
    78  	if err != nil {
    79  		klog.Fatalf("Write error: %s", err)
    80  	} else {
    81  		klog.Infof("Client sent: %s", msg)
    82  	}
    83  	return err
    84  }
    85  
    86  //UnixSock operates on unix domain sockets
    87  type UnixSock interface {
    88  	SendCommand(cmd string) ([]string, error)
    89  }
    90  
    91  //RealUnixSock is used for sending data through real unix domain sockets
    92  type RealUnixSock struct{}
    93  
    94  //SendCommand for the real unix sock for the actual program,
    95  func (r RealUnixSock) SendCommand(cmd string) ([]string, error) {
    96  	c, err := net.Dial("unix", IstgtUctlUnxpath)
    97  	if err != nil {
    98  		klog.Fatal("Dial error", err)
    99  	}
   100  	err = Writer(c, cmd+EndOfLine)
   101  	if err != nil {
   102  		c.Close()
   103  		return nil, err
   104  	}
   105  	resp := Reader(c, cmd)
   106  	c.Close()
   107  	return resp, err
   108  }
   109  
   110  //TestUnixSock is used as a dummy UnixSock
   111  type TestUnixSock struct{}
   112  
   113  //SendCommand for the real unix sock for the actual program,
   114  func (r TestUnixSock) SendCommand(cmd string) ([]string, error) {
   115  	return nil, nil
   116  }