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 }