func SendRequest(c *net.UnixConn, req *server.Request) error { payload, err := json.Marshal(req) if err != nil { return err } err = binary.Write(c, binary.BigEndian, uint32(len(payload))) if err != nil { return err } n, err := c.Write(payload) if err != nil { return err } else if n != len(payload) { return fmt.Errorf("Failed to write full payload, expected %v, wrote %v", len(payload), n) } if !req.HasFds { return nil } // Send filedescriptors with a 1 byte message. var oob []byte oob = syscall.UnixRights(req.Fds...) payload = make([]byte, 1) n, oobn, err := c.WriteMsgUnix(payload, oob, nil) if err != nil { return err } else if n != len(payload) || oobn != len(oob) { return fmt.Errorf("Error writing to socket, expected n=%v got %v, oob=%v got %v", len(payload), n, len(oob), oobn) } return nil }
func writeData(conn *net.UnixConn, files []*os.File, pid int, responseErr error) { var errMsg string = "" if responseErr != nil { errMsg = responseErr.Error() } response := &Response{ Pid: pid, ErrMessage: errMsg, } responseJson, _ := json.Marshal(response) // Ignore error args := make([]int, len(files)) for i, f := range files { args[i] = int(f.Fd()) } resp := syscall.UnixRights(args...) conn.WriteMsgUnix(responseJson, resp, nil) // Ignore error // Close the files whose descriptors have been sent to the host to ensure that // a close on the host takes effect in a timely fashion. for _, file := range files { file.Close() // Ignore error } }
func (t *unixTransport) SendMessage(msg *Message) error { fds := make([]int, 0) for i, v := range msg.Body { if fd, ok := v.(UnixFD); ok { msg.Body[i] = UnixFDIndex(len(fds)) fds = append(fds, int(fd)) } } if len(fds) != 0 { if !t.hasUnixFDs { return errors.New("dbus: unix fd passing not enabled") } msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds))) oob := syscall.UnixRights(fds...) buf := new(bytes.Buffer) msg.EncodeTo(buf, binary.LittleEndian) n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil) if err != nil { return err } if n != buf.Len() || oobn != len(oob) { return io.ErrShortWrite } } else { if err := msg.EncodeTo(t, binary.LittleEndian); err != nil { return nil } } return nil }
func Notify(state string, fds ...int) { ns := os.Getenv("NOTIFY_SOCKET") if ns == "" { return } addr := &net.UnixAddr{ Name: ns, Net: "unixgram", } conn, err := net.DialUnix("unixgram", nil, addr) if err != nil { return } defer conn.Close() if len(fds) > 0 { rights := syscall.UnixRights(fds...) conn.WriteMsgUnix([]byte(state), rights, nil) } else { conn.Write([]byte(state)) } }
func (m *Message) Write(arg interface{}) error { switch t := arg.(type) { case Proxy: return binary.Write(m.data, binary.LittleEndian, uint32(t.Id())) case uint32, int32: return binary.Write(m.data, binary.LittleEndian, t) case float32: f := float64ToFixed(float64(t)) return binary.Write(m.data, binary.LittleEndian, f) case string: str, _ := arg.(string) tail := 4 - (len(str) & 0x3) err := binary.Write(m.data, binary.LittleEndian, uint32(len(str)+tail)) if err != nil { return err } err = binary.Write(m.data, binary.LittleEndian, []byte(str)) if err != nil { return err } padding := make([]byte, tail) return binary.Write(m.data, binary.LittleEndian, padding) case uintptr: rights := syscall.UnixRights(int(t)) return binary.Write(m.control, binary.LittleEndian, rights) default: panic("Invalid Wayland request parameter type.") } return nil }
func (w *FDWriter) Write(b []byte) (int, error) { if len(w.fds) == 0 { return w.conn.Write(b) } else { rights := syscall.UnixRights(w.fds...) n, _, err := w.conn.WriteMsgUnix(b, rights, nil) w.fds = nil return n, err } }
func WriteFile(c *net.UnixConn, file *os.File, timeout time.Duration) error { if timeout > 0 { deadline := time.Now().Add(timeout) if err := c.SetWriteDeadline(deadline); err != nil { return err } } oob := syscall.UnixRights(int(file.Fd())) _, _, err := c.WriteMsgUnix(nil, oob, nil) return err }
func (fd Fd) writeTo(c *net.UnixConn) error { var b []byte oob := syscall.UnixRights(int(fd)) _, oobn, err := c.WriteMsgUnix(b, oob, nil) if err != nil { return err } if oobn != len(oob) { return fmt.Errorf("expected to write %d oob bytes, wrote %d", len(oob), oobn) } return nil }
func (usock *Usock) WriteFD(fd int) error { rights := syscall.UnixRights(fd) dummyByte := []byte("\000") n, oobn, err := usock.Conn.WriteMsgUnix(dummyByte, rights, nil) if err != nil { str := fmt.Sprintf("Usock#WriteFD:WriteMsgUnix: %v %v\n", err, syscall.EINVAL) return errors.New(str) } if n != 1 || oobn != len(rights) { str := fmt.Sprintf("Usock#WriteFD:WriteMsgUnix = %d, %d; want 1, %d\n", n, oobn, len(rights)) return errors.New(str) } return nil }
func (s *OOBUnixConn) Write(buf []byte) (int, error) { var oob []byte s.m.Lock() fds := s.sendFDs s.sendFDs = nil s.m.Unlock() if len(fds) > 0 { oob = syscall.UnixRights(fds...) } n, oobn, err := s.WriteMsgUnix(buf, oob, nil) if err == nil && oobn != len(oob) { err = ErrOOBSendFailed } return n, err }
func SendFd(conn *net.UnixConn, file *os.File) error { rights := syscall.UnixRights(int(file.Fd())) dummy := []byte("x") n, oobn, err := conn.WriteMsgUnix(dummy, rights, nil) if err != nil { return fmt.Errorf("sendfd: err %v", err) } if n != len(dummy) { return fmt.Errorf("sendfd: short write %v", conn) } if oobn != len(rights) { return fmt.Errorf("sendfd: short oob write %v", conn) } return nil }
func writeData(conn *net.UnixConn, response *container_daemon.ResponseMessage) { data, _ := json.Marshal(response) // Ignore error args := make([]int, len(response.Files)) for i, f := range response.Files { args[i] = int(f.Fd()) } oobData := syscall.UnixRights(args...) conn.WriteMsgUnix(data, oobData, nil) // Ignore error // Close the files whose descriptors have been sent to the host to ensure that // a close on the host takes effect in a timely fashion. for _, file := range response.Files { file.Close() // Ignore error } }
// passFDChild is the child process used by TestPassFD. func passFDChild() { defer os.Exit(0) // Look for our fd. It should be fd 3, but we work around an fd leak // bug here (http://golang.org/issue/2603) to let it be elsewhere. var uc *net.UnixConn for fd := uintptr(3); fd <= 10; fd++ { f := os.NewFile(fd, "unix-conn") var ok bool netc, _ := net.FileConn(f) uc, ok = netc.(*net.UnixConn) if ok { break } } if uc == nil { fmt.Println("failed to find unix fd") return } // Make a file f to send to our parent process on uc. // We make it in tempDir, which our parent will clean up. flag.Parse() tempDir := flag.Arg(0) f, err := ioutil.TempFile(tempDir, "") if err != nil { fmt.Printf("TempFile: %v", err) return } f.Write([]byte("Hello from child process!\n")) f.Seek(0, 0) rights := syscall.UnixRights(int(f.Fd())) dummyByte := []byte("x") n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil) if err != nil { fmt.Printf("WriteMsgUnix: %v", err) return } if n != 1 || oobn != len(rights) { fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights)) return } }
func (u *Usock) WriteFD(fd int) error { u.Lock() defer u.Unlock() rights := syscall.UnixRights(fd) dummyByte := []byte{0} n, oobn, err := u.reader.Conn.WriteMsgUnix(dummyByte, rights, nil) if err != nil { str := fmt.Sprintf("Usock#WriteFD:WriteMsgUnix: %v / %v\n", err, syscall.EINVAL) return errors.New(str) } if n != 1 || oobn != len(rights) { str := fmt.Sprintf("Usock#WriteFD:WriteMsgUnix = %d, %d; want 1, %d\n", n, oobn, len(rights)) return errors.New(str) } return nil }
func (c *Conn) WriteMessage(m *Message) (err error) { var payload []byte if m.p != nil { payload = m.p.Bytes() } if err = c.writeHeader(m.object, m.opcode, uint16(len(payload))); err != nil { return } if len(payload) == 0 { // message without payload wouldn't contain fds, so we can return here return nil } var oob []byte if len(m.fds) != 0 { oob = syscall.UnixRights(m.fds...) } _, _, err = c.c.WriteMsgUnix(payload, oob, nil) return }
func (conn *UnixConn) sendUnix(data []byte, fds ...int) error { header, err := makeHeader(data, fds) if err != nil { return err } // There is a bug in conn.WriteMsgUnix where it doesn't correctly return // the number of bytes writte (http://code.google.com/p/go/issues/detail?id=7645) // So, we can't rely on the return value from it. However, we must use it to // send the fds. In order to handle this we only write one byte using WriteMsgUnix // (when we have to), as that can only ever block or fully suceed. We then write // the rest with conn.Write() // The reader side should not rely on this though, as hopefully this gets fixed // in go later. written := 0 if len(fds) != 0 { oob := syscall.UnixRights(fds...) wrote, _, err := conn.WriteMsgUnix(header[0:1], oob, nil) if err != nil { return err } written = written + wrote } for written < len(header) { wrote, err := conn.Write(header[written:]) if err != nil { return err } written = written + wrote } written = 0 for written < len(data) { wrote, err := conn.Write(data[written:]) if err != nil { return err } written = written + wrote } return nil }
func sendmsg(msg *message) { size := len(msg.buf.Bytes()) buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, msg.obj.Id()) binary.Write(buf, binary.LittleEndian, msg.opcode) binary.Write(buf, binary.LittleEndian, int16(size+8)) binary.Write(buf, binary.LittleEndian, msg.buf.Bytes()) var cmsgbytes []byte if msg.fd != 0 { cmsgbytes = syscall.UnixRights(int(msg.fd)) } _, _, err := conn.unixconn.WriteMsgUnix(buf.Bytes(), cmsgbytes, nil) if err != nil { fmt.Println("sendmsg", err) return } syscall.Close(int(msg.fd)) }
// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, // and ParseUnixRights are able to successfully round-trip lists of file descriptors. func TestUnixRightsRoundtrip(t *testing.T) { testCases := [...][][]int{ {{42}}, {{1, 2}}, {{3, 4, 5}}, {{}}, {{1, 2}, {3, 4, 5}, {}, {7}}, } for _, testCase := range testCases { b := []byte{} var n int for _, fds := range testCase { // Last assignment to n wins n = len(b) + syscall.CmsgLen(4*len(fds)) b = append(b, syscall.UnixRights(fds...)...) } // Truncate b b = b[:n] scms, err := syscall.ParseSocketControlMessage(b) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } if len(scms) != len(testCase) { t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) } for i, scm := range scms { gotFds, err := syscall.ParseUnixRights(&scm) if err != nil { t.Fatalf("ParseUnixRights: %v", err) } wantFds := testCase[i] if len(gotFds) != len(wantFds) { t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) } for j, fd := range gotFds { if fd != wantFds[j] { t.Fatalf("expected fd %v, got %v", wantFds[j], fd) } } } } }
func acceptConnection(listener net.Listener, stdoutR, stderrR, statusR *os.File) (net.Conn, error) { conn, err := listener.Accept() if err != nil { return nil, err } rights := syscall.UnixRights( int(stdoutR.Fd()), int(stderrR.Fd()), int(statusR.Fd()), ) _, _, err = conn.(*net.UnixConn).WriteMsgUnix([]byte{}, rights, nil) if err != nil { return nil, err } return conn, nil }
func newNetworkAddSession(ctx *hypervisor.VmContext, qc *QemuContext, id string, fd uint64, device, mac string, index, addr int, result chan<- hypervisor.VmEvent) { busAddr := fmt.Sprintf("0x%x", addr) commands := make([]*QmpCommand, 3) scm := syscall.UnixRights(int(fd)) glog.V(1).Infof("send net to qemu at %d", int(fd)) commands[0] = &QmpCommand{ Execute: "getfd", Arguments: map[string]interface{}{ "fdname": "fd" + device, }, Scm: scm, } commands[1] = &QmpCommand{ Execute: "netdev_add", Arguments: map[string]interface{}{ "type": "tap", "id": device, "fd": "fd" + device, }, } commands[2] = &QmpCommand{ Execute: "device_add", Arguments: map[string]interface{}{ "netdev": device, "driver": "virtio-net-pci", "disable-modern": "off", "disable-legacy": "on", "bus": "pci.0", "addr": busAddr, "mac": mac, "id": device, }, } qc.qmp <- &QmpSession{ commands: commands, respond: defaultRespond(result, &hypervisor.NetDevInsertedEvent{ Id: id, Index: index, DeviceName: device, Address: addr, }), } }
// Put sends file descriptors to Unix domain socket. // // Please note that the number of descriptors in one message is limited // and is rather small. // Use conn.File() to get a file if you want to put a network connection. func Put(via *net.UnixConn, files ...*os.File) error { if len(files) == 0 { return nil } viaf, err := via.File() if err != nil { return err } socket := int(viaf.Fd()) defer viaf.Close() fds := make([]int, len(files)) for i := range files { fds[i] = int(files[i].Fd()) } rights := syscall.UnixRights(fds...) return syscall.Sendmsg(socket, nil, rights, nil, 0) }
func newNetworkAddSession(qc *QemuContext, fd uint64, device, mac string, index, addr int) { busAddr := fmt.Sprintf("0x%x", addr) commands := make([]*QmpCommand, 3) scm := syscall.UnixRights(int(fd)) glog.V(1).Infof("send net to qemu at %d", int(fd)) commands[0] = &QmpCommand{ Execute: "getfd", Arguments: map[string]interface{}{ "fdname": "fd" + device, }, Scm: scm, } commands[1] = &QmpCommand{ Execute: "netdev_add", Arguments: map[string]interface{}{ "type": "tap", "id": device, "fd": "fd" + device, }, } commands[2] = &QmpCommand{ Execute: "device_add", Arguments: map[string]interface{}{ "driver": "virtio-net-pci", "netdev": device, "mac": mac, "bus": "pci.0", "addr": busAddr, "id": device, }, } qc.qmp <- &QmpSession{ commands: commands, callback: &hypervisor.NetDevInsertedEvent{ Index: index, DeviceName: device, Address: addr, }, } }
// Send a message to the local systemd journal. vars is a map of journald // fields to values. Fields must be composed of uppercase letters, numbers, // and underscores, but must not start with an underscore. Within these // restrictions, any arbitrary field name may be used. Some names have special // significance: see the journalctl documentation // (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) // for more details. vars may be nil. func Send(message string, priority Priority, vars map[string]string) error { if conn == nil { return journalError("could not connect to journald socket") } data := new(bytes.Buffer) appendVariable(data, "PRIORITY", strconv.Itoa(int(priority))) appendVariable(data, "MESSAGE", message) for k, v := range vars { appendVariable(data, k, v) } _, err := io.Copy(conn, data) if err != nil && isSocketSpaceError(err) { file, err := tempFd() if err != nil { return journalError(err.Error()) } defer file.Close() _, err = io.Copy(file, data) if err != nil { return journalError(err.Error()) } rights := syscall.UnixRights(int(file.Fd())) /* this connection should always be a UnixConn, but better safe than sorry */ unixConn, ok := conn.(*net.UnixConn) if !ok { return journalError("can't send file through non-Unix connection") } unixConn.WriteMsgUnix([]byte{}, rights, nil) } else if err != nil { return journalError(err.Error()) } return nil }
func sendUnix(conn *net.UnixConn, data []byte, fds ...int) error { _, _, err := conn.WriteMsgUnix(data, syscall.UnixRights(fds...), nil) return err }
func sendrequest(obj Object, req string, args ...interface{}) { if conn.alive != true { return } data := new(bytes.Buffer) dbg := new(bytes.Buffer) size := 8 fd := uintptr(0) signature := signatures[req] opcode := signature.opcode sig := signature.signature for i, arg := range args { switch sig[i] { case 'i', 'f': size += 4 binary.Write(data, binary.LittleEndian, arg.(int32)) fmt.Fprintf(dbg, "%d ", arg) case 'u': size += 4 binary.Write(data, binary.LittleEndian, arg.(uint32)) fmt.Fprintf(dbg, "%d ", arg) case 'h': fd, _, _ = syscall.Syscall(syscall.SYS_FCNTL, arg.(uintptr), syscall.F_DUPFD_CLOEXEC, 0) case 'o': size += 4 binary.Write(data, binary.LittleEndian, arg.(Object).Id()) fmt.Fprintf(dbg, "%d ", arg.(Object).Id()) case 'n': size += 4 nobj := arg.(Object) appendObject(nobj) binary.Write(data, binary.LittleEndian, nobj.Id()) fmt.Fprintf(dbg, "new_id %d ", nobj.Id()) case 's': // First get padding str := arg.(string) pad := 4 - (len(str) % 4) binary.Write(data, binary.LittleEndian, int32(len(str)+pad)) binary.Write(data, binary.LittleEndian, []byte(str)) for i := 0; i < pad; i++ { binary.Write(data, binary.LittleEndian, []byte{0}) } size += len(str) + pad + 4 fmt.Fprintf(dbg, "%s ", str) } } fmt.Printf(" -> %s@%d ( %s)\n", req, obj.Id(), dbg) // Send message buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, obj.Id()) binary.Write(buf, binary.LittleEndian, opcode) binary.Write(buf, binary.LittleEndian, int16(size)) binary.Write(buf, binary.LittleEndian, data.Bytes()) var cmsgbytes []byte if fd != 0 { cmsgbytes = syscall.UnixRights(int(fd)) } _, _, err := conn.unixconn.WriteMsgUnix(buf.Bytes(), cmsgbytes, nil) if err != nil { fmt.Println("sendrequest", err) os.Exit(1) return } syscall.Close(int(fd)) }
func (mc *MsgConn) sendWithFds(data []byte, fds []int) error { oob := syscall.UnixRights(fds...) _, _, err := mc.conn.WriteMsgUnix(data, oob, nil) return err }
var ( stdoutR, stderrR, statusR *os.File ) stdoutR, stdoutW, err = os.Pipe() Expect(err).ToNot(HaveOccurred()) stderrR, stderrW, err = os.Pipe() Expect(err).ToNot(HaveOccurred()) statusR, statusW, err = os.Pipe() Expect(err).ToNot(HaveOccurred()) fakeServer.SetConnectionHandler(func(conn net.Conn) { rights := syscall.UnixRights( int(stdoutR.Fd()), int(stderrR.Fd()), int(statusR.Fd()), ) conn.(*net.UnixConn).WriteMsgUnix([]byte{}, rights, nil) }) }) JustBeforeEach(func() { go fakeServer.Serve() }) AfterEach(func() { Expect(fakeServer.Stop()).To(Succeed()) Expect(os.RemoveAll(path.Base(unixSockerPath))).To(Succeed())