SendMsg implements the linux syscall sendmsg(2) for unix sockets backed by a transport.Endpoint.
(t *kernel.Task, src usermem.IOSequence, to []byte, flags int, haveDeadline bool, deadline ktime.Time, controlMessages socket.ControlMessages)
| 645 | // SendMsg implements the linux syscall sendmsg(2) for unix sockets backed by |
| 646 | // a transport.Endpoint. |
| 647 | func (s *Socket) SendMsg(t *kernel.Task, src usermem.IOSequence, to []byte, flags int, haveDeadline bool, deadline ktime.Time, controlMessages socket.ControlMessages) (int, *syserr.Error) { |
| 648 | w := EndpointWriter{ |
| 649 | Ctx: t, |
| 650 | Endpoint: s.ep, |
| 651 | Control: controlMessages.Unix, |
| 652 | To: nil, |
| 653 | } |
| 654 | if len(to) > 0 { |
| 655 | switch s.stype { |
| 656 | case linux.SOCK_SEQPACKET: |
| 657 | // to is ignored. |
| 658 | case linux.SOCK_STREAM: |
| 659 | if s.State() == linux.SS_CONNECTED { |
| 660 | return 0, syserr.ErrAlreadyConnected |
| 661 | } |
| 662 | return 0, syserr.ErrNotSupported |
| 663 | default: |
| 664 | ep, err := s.extractEndpoint(t, to) |
| 665 | if err != nil { |
| 666 | return 0, err |
| 667 | } |
| 668 | defer ep.Release(t) |
| 669 | w.To = ep |
| 670 | |
| 671 | if ep.Passcred() && w.Control.Credentials == nil { |
| 672 | w.Control.Credentials = control.MakeCreds(t) |
| 673 | } |
| 674 | } |
| 675 | } |
| 676 | |
| 677 | n, err := src.CopyInTo(t, &w) |
| 678 | if w.Notify != nil { |
| 679 | w.Notify() |
| 680 | } |
| 681 | if err != linuxerr.ErrWouldBlock || flags&linux.MSG_DONTWAIT != 0 { |
| 682 | return int(n), syserr.FromError(err) |
| 683 | } |
| 684 | |
| 685 | // Only send SCM Rights once (see net/unix/af_unix.c:unix_stream_sendmsg). |
| 686 | w.Control.Rights = nil |
| 687 | |
| 688 | // We'll have to block. Register for notification and keep trying to |
| 689 | // send all the data. |
| 690 | e, ch := waiter.NewChannelEntry(waiter.WritableEvents) |
| 691 | s.EventRegister(&e) |
| 692 | defer s.EventUnregister(&e) |
| 693 | |
| 694 | total := n |
| 695 | for { |
| 696 | // Shorten src to reflect bytes previously written. |
| 697 | src = src.DropFirst64(n) |
| 698 | |
| 699 | n, err = src.CopyInTo(t, &w) |
| 700 | if w.Notify != nil { |
| 701 | w.Notify() |
| 702 | } |
| 703 | total += n |
| 704 | if err != linuxerr.ErrWouldBlock { |
nothing calls this directly
no test coverage detected