go.ligato.io/vpp-agent/v3@v3.5.0/tests/e2e/e2etest/connection.go (about) 1 // Copyright (c) 2020 Cisco and/or its affiliates. 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 e2etest 16 17 import ( 18 "bufio" 19 "context" 20 "fmt" 21 "log" 22 "net" 23 "strings" 24 "time" 25 ) 26 27 // TCP or UDP connection request 28 type connectionRequest struct { 29 conn net.Conn 30 err error 31 } 32 33 func simpleTCPServer(ctx context.Context, ms *Microservice, addr string, expReqMsg, respMsg string, done chan<- error, logger *log.Logger) { 34 defer func() { 35 done <- nil 36 }() 37 // move to the network namespace where server should listen 38 exitNetNs := ms.EnterNetNs() 39 defer exitNetNs() 40 41 listener, err := net.Listen("tcp", addr) 42 if err != nil { 43 done <- err 44 return 45 } 46 defer listener.Close() 47 48 // accept single connection 49 newConn := make(chan connectionRequest, 1) 50 go func() { 51 conn, err := listener.Accept() 52 if err != nil { 53 err = fmt.Errorf("accept failed with: %v", err) 54 logger.Println(err) 55 } 56 newConn <- connectionRequest{conn: conn, err: err} 57 close(newConn) 58 }() 59 60 // wait for connection 61 var cr connectionRequest 62 select { 63 case <-ctx.Done(): 64 done <- fmt.Errorf("tcp server listening on %s was canceled", addr) 65 return 66 case cr = <-newConn: 67 if cr.err != nil { 68 done <- cr.err 69 return 70 } 71 defer cr.conn.Close() 72 } 73 74 // communicate with the client 75 commRv := make(chan error, 1) 76 go func() { 77 defer close(commRv) 78 // receive message from the client 79 message, err := bufio.NewReader(cr.conn).ReadString('\n') 80 if err != nil { 81 err = fmt.Errorf("failed to read data from client: %v", err) 82 logger.Println(err) 83 commRv <- err 84 return 85 } 86 // send response to the client 87 _, err = cr.conn.Write([]byte(respMsg + "\n")) 88 if err != nil { 89 err = fmt.Errorf("failed to send data to client: %v", err) 90 logger.Println(err) 91 commRv <- err 92 return 93 } 94 // check if the exchanged data are as expected 95 message = strings.TrimRight(message, "\n") 96 if message != expReqMsg { 97 err = fmt.Errorf("unexpected message received from client ('%s' vs. '%s')", 98 message, expReqMsg) 99 logger.Println(err) 100 commRv <- err 101 return 102 } 103 commRv <- nil 104 }() 105 106 // wait for the message exchange to execute 107 select { 108 case <-ctx.Done(): 109 done <- fmt.Errorf("tcp server listening on %s was canceled", addr) 110 return 111 case err = <-commRv: 112 done <- err 113 } 114 115 // do not close until client confirms reception of the message 116 <-ctx.Done() 117 } 118 119 func simpleUDPServer(ctx context.Context, ms *Microservice, addr string, expReqMsg, respMsg string, done chan<- error, ready chan<- error, logger *log.Logger) { 120 defer func() { 121 done <- nil 122 }() 123 124 const maxBufferSize = 1024 125 // move to the network namespace where server should listen 126 exitNetNs := ms.EnterNetNs() 127 defer exitNetNs() 128 129 conn, err := net.ListenPacket("udp", addr) 130 ready <- err 131 if err != nil { 132 done <- err 133 return 134 } 135 defer conn.Close() 136 137 // communicate with the client 138 commRv := make(chan error, 1) 139 go func() { 140 defer close(commRv) 141 // receive message from the client 142 buffer := make([]byte, maxBufferSize) 143 n, addr, err := conn.ReadFrom(buffer) 144 if err != nil { 145 err = fmt.Errorf("failed to read data from client: %v", err) 146 logger.Println(err) 147 commRv <- err 148 return 149 } 150 message := string(buffer[:n]) 151 // send response to the client 152 _, err = conn.WriteTo([]byte(respMsg+"\n"), addr) 153 if err != nil { 154 err = fmt.Errorf("failed to send data to client: %v", err) 155 logger.Println(err) 156 commRv <- err 157 return 158 } 159 // check if the exchanged data are as expected 160 message = strings.TrimRight(message, "\n") 161 if message != expReqMsg { 162 err = fmt.Errorf("unexpected message received from client ('%s' vs. '%s')", 163 message, expReqMsg) 164 logger.Println(err) 165 commRv <- err 166 return 167 } 168 commRv <- nil 169 }() 170 171 // wait for the message exchange to execute 172 select { 173 case <-ctx.Done(): 174 done <- fmt.Errorf("udp server listening on %s was canceled", addr) 175 return 176 case err = <-commRv: 177 done <- err 178 } 179 180 // do not close until client confirms reception of the message 181 <-ctx.Done() 182 } 183 184 func simpleTCPClient(ms *Microservice, addr string, reqMsg, expRespMsg string, timeout time.Duration, done chan<- error, logger *log.Logger) { 185 // try to connect with the server 186 newConn := make(chan connectionRequest, 1) 187 188 go func() { 189 // move to the network namespace from which the connection should be initiated 190 exitNetNs := ms.EnterNetNs() 191 defer exitNetNs() 192 start := time.Now() 193 for { 194 conn, err := net.Dial("tcp", addr) 195 if err != nil && time.Since(start) < timeout { 196 time.Sleep(checkPollingInterval) 197 continue 198 } 199 if err != nil { 200 err = fmt.Errorf("dial failed with: %v", err) 201 logger.Println(err) 202 } 203 newConn <- connectionRequest{conn: conn, err: err} 204 break 205 } 206 close(newConn) 207 }() 208 209 simpleTCPOrUDPClient(newConn, addr, reqMsg, expRespMsg, timeout, done, logger) 210 } 211 212 func simpleUDPClient(ms *Microservice, addr string, reqMsg, expRespMsg string, timeout time.Duration, done chan<- error, srvReady chan error, logger *log.Logger) { 213 // try to connect with the server 214 newConn := make(chan connectionRequest, 1) 215 216 go func() { 217 // move to the network namespace from which the connection should be initiated 218 exitNetNs := ms.EnterNetNs() 219 defer exitNetNs() 220 udpAddr, err := net.ResolveUDPAddr("udp", addr) 221 if err != nil { 222 err = fmt.Errorf("dial failed with: %v", err) 223 logger.Println(err) 224 newConn <- connectionRequest{conn: nil, err: err} 225 } else { 226 start := time.Now() 227 err = <-srvReady 228 if err != nil { 229 err = fmt.Errorf("dial failed with: %v", "server not ready") 230 logger.Println(err) 231 newConn <- connectionRequest{conn: nil, err: err} 232 } else { 233 for { 234 conn, err := net.DialUDP("udp", nil, udpAddr) 235 if err != nil && time.Since(start) < timeout { 236 time.Sleep(checkPollingInterval) 237 continue 238 } 239 if err != nil { 240 err = fmt.Errorf("dial failed with: %v", err) 241 logger.Println(err) 242 } 243 newConn <- connectionRequest{conn: conn, err: err} 244 break 245 } 246 } 247 } 248 close(newConn) 249 }() 250 251 simpleTCPOrUDPClient(newConn, addr, reqMsg, expRespMsg, timeout, done, logger) 252 } 253 254 func simpleTCPOrUDPClient(newConn chan connectionRequest, addr, reqMsg, expRespMsg string, 255 timeout time.Duration, done chan<- error, logger *log.Logger) { 256 257 // wait for connection 258 var cr connectionRequest 259 select { 260 case <-time.After(timeout): 261 done <- fmt.Errorf("connection to %s timed out", addr) 262 return 263 case cr = <-newConn: 264 if cr.err != nil { 265 done <- cr.err 266 return 267 } 268 defer cr.conn.Close() 269 } 270 271 // communicate with the server 272 commRv := make(chan error, 1) 273 go func() { 274 defer close(commRv) 275 276 // send message to the server 277 _, err := cr.conn.Write([]byte(reqMsg + "\n")) 278 if err != nil { 279 err = fmt.Errorf("failed to send data to the server: %v", err) 280 logger.Println(err) 281 commRv <- err 282 return 283 } 284 // listen for reply 285 start := time.Now() 286 var message string 287 for { 288 message, err = bufio.NewReader(cr.conn).ReadString('\n') 289 if err != nil && time.Since(start) < timeout { 290 time.Sleep(checkPollingInterval) 291 continue 292 } 293 if err != nil { 294 err = fmt.Errorf("failed to read data from server: %v", err) 295 logger.Println(err) 296 commRv <- err 297 return 298 } 299 break 300 } 301 // check if the exchanged data are as expected 302 message = strings.TrimRight(message, "\n") 303 if message != expRespMsg { 304 err = fmt.Errorf("unexpected message received from server ('%s' vs. '%s')", 305 message, expRespMsg) 306 logger.Println(err) 307 commRv <- err 308 return 309 } 310 311 commRv <- nil 312 }() 313 314 // wait for the message exchange to execute 315 select { 316 case <-time.After(timeout): 317 done <- fmt.Errorf("communication with %s timed out", addr) 318 case err := <-commRv: 319 done <- err 320 } 321 }