func (t *testAttachServer) Start() error { log.Info("opening ttyS0 pipe pair for backchannel (server)") c, err := os.OpenFile(pathPrefix+"/ttyS0c", os.O_WRONLY|syscall.O_NOCTTY, 0777) if err != nil { detail := fmt.Sprintf("failed to open cpipe for backchannel: %s", err) log.Error(detail) return errors.New(detail) } s, err := os.OpenFile(pathPrefix+"/ttyS0s", os.O_RDONLY|syscall.O_NOCTTY, 0777) if err != nil { detail := fmt.Sprintf("failed to open spipe for backchannel: %s", err) log.Error(detail) return errors.New(detail) } log.Infof("creating raw connection from ttyS0 pipe pair (c=%d, s=%d)\n", c.Fd(), s.Fd()) var conn net.Conn conn, err = serial.NewHalfDuplexFileConn(s, c, pathPrefix+"/ttyS0", "file") if err != nil { detail := fmt.Sprintf("failed to create raw connection from ttyS0 pipe pair: %s", err) log.Error(detail) return errors.New(detail) } t.conn.Lock() defer t.conn.Unlock() t.conn.conn = conn return nil }
// create client on the mock pipe func mockBackChannel(ctx context.Context) (net.Conn, error) { log.Info("opening ttyS0 pipe pair for backchannel (client)") c, err := os.OpenFile(pathPrefix+"/ttyS0c", os.O_RDONLY|syscall.O_NOCTTY, 0777) if err != nil { detail := fmt.Sprintf("failed to open cpipe for backchannel: %s", err) log.Error(detail) return nil, errors.New(detail) } s, err := os.OpenFile(pathPrefix+"/ttyS0s", os.O_WRONLY|syscall.O_NOCTTY, 0777) if err != nil { detail := fmt.Sprintf("failed to open spipe for backchannel: %s", err) log.Error(detail) return nil, errors.New(detail) } log.Infof("creating raw connection from ttyS0 pipe pair (c=%d, s=%d)\n", c.Fd(), s.Fd()) conn, err := serial.NewHalfDuplexFileConn(c, s, pathPrefix+"/ttyS0", "file") if err != nil { detail := fmt.Sprintf("failed to create raw connection from ttyS0 pipe pair: %s", err) log.Error(detail) return nil, errors.New(detail) } // HACK: currently RawConn dosn't implement timeout so throttle the spinning ticker := time.NewTicker(1000 * time.Millisecond) for { select { case <-ticker.C: // FIXME: need to implement timeout of purging hangs with no content // on the pipe // serial.PurgeIncoming(ctx, conn) err := serial.HandshakeClient(conn, true) if err != nil { if err == io.EOF { // with unix pipes the open will block until both ends are open, therefore // EOF means the other end has been intentionally closed return nil, err } log.Error(err) } else { return conn, nil } case <-ctx.Done(): conn.Close() ticker.Stop() return nil, ctx.Err() } } }
// create client on the mock pipe and dial the given host:port func mockNetworkToSerialConnection(host string) (*sync.WaitGroup, error) { log.Info("opening ttyS0 pipe pair for backchannel") c, err := os.OpenFile(pathPrefix+"/ttyS0c", os.O_RDONLY|syscall.O_NOCTTY, 0777) if err != nil { return nil, fmt.Errorf("failed to open cpipe for backchannel: %s", err) } s, err := os.OpenFile(pathPrefix+"/ttyS0s", os.O_WRONLY|syscall.O_NOCTTY, 0777) if err != nil { return nil, fmt.Errorf("failed to open spipe for backchannel: %s", err) } log.Infof("creating raw connection from ttyS0 pipe pair (c=%d, s=%d)\n", c.Fd(), s.Fd()) fconn, err := serial.NewHalfDuplexFileConn(c, s, pathPrefix+"/ttyS0", "file") if err != nil { return nil, fmt.Errorf("failed to create raw connection from ttyS0 pipe pair: %s", err) } // Dial the attach server. This is a TCP client networkClientCon, err := net.Dial("tcp", host) if err != nil { return nil, err } log.Debugf("dialed %s", host) wg := sync.WaitGroup{} wg.Add(2) go func() { io.Copy(networkClientCon, fconn) wg.Done() }() go func() { io.Copy(fconn, networkClientCon) wg.Done() }() return &wg, nil }