SendMsg implements the linux syscall sendmsg(2) for sockets backed by tcpip.Endpoint.
(t *kernel.Task, src usermem.IOSequence, to []byte, flags int, haveDeadline bool, deadline ktime.Time, controlMessages socket.ControlMessages)
| 3367 | // SendMsg implements the linux syscall sendmsg(2) for sockets backed by |
| 3368 | // tcpip.Endpoint. |
| 3369 | func (s *sock) SendMsg(t *kernel.Task, src usermem.IOSequence, to []byte, flags int, haveDeadline bool, deadline ktime.Time, controlMessages socket.ControlMessages) (int, *syserr.Error) { |
| 3370 | // Reject Unix control messages. |
| 3371 | if !controlMessages.Unix.Empty() { |
| 3372 | return 0, syserr.ErrInvalidArgument |
| 3373 | } |
| 3374 | |
| 3375 | var addr *tcpip.FullAddress |
| 3376 | if len(to) > 0 { |
| 3377 | addrBuf, family, err := socket.AddressAndFamily(to) |
| 3378 | if err != nil { |
| 3379 | return 0, err |
| 3380 | } |
| 3381 | if !s.checkFamily(family, false /* exact */) { |
| 3382 | return 0, syserr.ErrInvalidArgument |
| 3383 | } |
| 3384 | addrBuf = s.mapFamily(addrBuf, family) |
| 3385 | |
| 3386 | addr = &addrBuf |
| 3387 | } |
| 3388 | |
| 3389 | opts := tcpip.WriteOptions{ |
| 3390 | To: addr, |
| 3391 | More: flags&linux.MSG_MORE != 0, |
| 3392 | EndOfRecord: flags&linux.MSG_EOR != 0, |
| 3393 | ControlMessages: s.linuxToNetstackControlMessages(controlMessages), |
| 3394 | } |
| 3395 | |
| 3396 | r := src.Reader(t) |
| 3397 | var ( |
| 3398 | total int64 |
| 3399 | entry waiter.Entry |
| 3400 | ch <-chan struct{} |
| 3401 | ) |
| 3402 | for { |
| 3403 | n, err := s.Endpoint.Write(r, opts) |
| 3404 | total += n |
| 3405 | if flags&linux.MSG_DONTWAIT != 0 { |
| 3406 | return int(total), syserr.TranslateNetstackError(err) |
| 3407 | } |
| 3408 | block := true |
| 3409 | switch err.(type) { |
| 3410 | case nil: |
| 3411 | block = total != src.NumBytes() |
| 3412 | case *tcpip.ErrWouldBlock: |
| 3413 | default: |
| 3414 | block = false |
| 3415 | } |
| 3416 | if block { |
| 3417 | if ch == nil { |
| 3418 | // We'll have to block. Register for notification and keep trying to |
| 3419 | // send all the data. |
| 3420 | entry, ch = waiter.NewChannelEntry(waiter.WritableEvents) |
| 3421 | s.EventRegister(&entry) |
| 3422 | defer s.EventUnregister(&entry) |
| 3423 | } else { |
| 3424 | // Don't wait immediately after registration in case more data |
| 3425 | // became available between when we last checked and when we setup |
| 3426 | // the notification. |
nothing calls this directly
no test coverage detected