public bool TryCompleteReceive(Ring ring, int result, [NotNullWhen(true)] out InboundConnection connection) { // Start work-around for https://github.com/axboe/liburing/issues/128 _iov.AsSpan().Clear(); _dummyBuffer.AsSpan().Clear(); _control.AsSpan().Clear(); _header.AsSpan().Clear(); iovec* iov = (iovec*) MemoryHelper.UnsafeGetAddressOfPinnedArrayData(_iov); iov->iov_base = (byte*) MemoryHelper.UnsafeGetAddressOfPinnedArrayData(_dummyBuffer); iov->iov_len = 1; byte* control = (byte*) MemoryHelper.UnsafeGetAddressOfPinnedArrayData(_control); msghdr* header = (msghdr*) MemoryHelper.UnsafeGetAddressOfPinnedArrayData(_header); header->msg_iov = iov; header->msg_iovlen = 1; header->msg_control = control; header->msg_controllen = _control.Length; result = _recipient.RecvMsg(header, (MSG_NOSIGNAL | MSG_CMSG_CLOEXEC)); // End of work-around for https://github.com/axboe/liburing/issues/128 connection = default; if (result < 0) { HandleCompleteReceiveError(ring, result); return false; } bool receivedSocket = false; LinuxSocket socket = default; for (cmsghdr* cmsg = CMSG_FIRSTHDR(header); cmsg != null; cmsg = CMSG_NXTHDR(header, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int* fdptr = (int*) CMSG_DATA(cmsg); socket = *fdptr; socket.SetFlag(O_NONBLOCK); receivedSocket = true; break; } } if (!receivedSocket) { if (result != 0) { PollReceive(ring); } return false; } connection = new InboundConnection(socket, _endPoint, null, _memoryPool, _options, _scheduler); return true; }
internal unsafe override int Read(byte[] buffer, int offset, int count, UnixFDArray fdArray) { if (!Connection.UnixFDSupported || fdArray == null) { return(base.Read(buffer, offset, count, fdArray)); } if (count < 0 || offset < 0 || count + offset < count || count + offset > buffer.Length) { throw new ArgumentException(); fixed(byte *ptr = buffer) { IOVector iov = new IOVector(); iov.Base = ptr + offset; iov.Length = count; msghdr msg = new msghdr(); msg.msg_iov = &iov; msg.msg_iovlen = 1; byte[] cmsg = new byte[CMSG_LEN((ulong)(sizeof(int) * UnixFDArray.MaxFDs))]; fixed(byte *cmsgPtr = cmsg) { msg.msg_control = (IntPtr)(cmsgPtr); msg.msg_controllen = (uint)cmsg.Length; int read = socket.RecvMsg(&msg, 0); for (cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr != null; hdr = CMSG_NXTHDR(&msg, hdr)) { if (hdr->cmsg_level != 1) //SOL_SOCKET { continue; } if (hdr->cmsg_type != 0x01) //SCM_RIGHTS { continue; } int *data = (int *)CMSG_DATA(hdr); int fdCount = (int)(((ulong)hdr->cmsg_len - CMSG_LEN(0)) / sizeof(int)); for (int i = 0; i < fdCount; i++) { fdArray.FDs.Add(new UnixFD(data[i])); } } if ((msg.msg_flags & 0x08) != 0) // MSG_CTRUNC { throw new Exception("Control message truncated"); } return(read); } } }
public unsafe static PosixResult ReceiveSocket(int fromSocket, out int socket, bool blocking) { socket = -1; byte dummyBuffer = 0; iovec iov = default(iovec); iov.iov_base = &dummyBuffer; iov.iov_len = 1; int controlLength = CMSG_SPACE(sizeof(int)); byte *control = stackalloc byte[controlLength]; msghdr header = default(msghdr); header.msg_iov = &iov; header.msg_iovlen = 1; header.msg_control = control; header.msg_controllen = controlLength; int flags = MSG_NOSIGNAL | MSG_CMSG_CLOEXEC; ssize_t rv; do { rv = recvmsg(fromSocket, &header, flags); } while (rv < 0 && errno == EINTR); if (rv != -1) { for (cmsghdr *cmsg = CMSG_FIRSTHDR(&header); cmsg != null; cmsg = CMSG_NXTHDR(&header, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int *fdptr = (int *)CMSG_DATA(cmsg); socket = *fdptr; flags = fcntl(socket, F_GETFL, 0); if (blocking) { flags &= ~O_NONBLOCK; } else { flags |= O_NONBLOCK; } fcntl(socket, F_SETFL, flags); break; } } } return(PosixResult.FromReturnValue(rv)); }
static unsafe cmsghdr *CMSG_NXTHDR(msghdr *mhdr, cmsghdr *cmsg) { if ((long)cmsg->cmsg_len < sizeof(cmsghdr)) { return(null); } cmsg = (cmsghdr *)((byte *)cmsg + CMSG_ALIGN((ulong)cmsg->cmsg_len)); if ((byte *)(cmsg + 1) > (byte *)mhdr->msg_control + mhdr->msg_controllen || (byte *)cmsg + CMSG_ALIGN((ulong)cmsg->cmsg_len) > (byte *)mhdr->msg_control + mhdr->msg_controllen) return(null); }
public unsafe static PosixResult AcceptAndSendHandleTo(Socket fromSocket, int toSocket) { int acceptFd = fromSocket.DangerousGetHandle().ToInt32(); ssize_t rv; do { rv = accept4(acceptFd, null, null, SOCK_CLOEXEC); } while (rv < 0 && errno == EINTR); if (rv != -1) { int acceptedFd = (int)rv; byte dummyBuffer = 0; iovec iov = default(iovec); iov.iov_base = &dummyBuffer; iov.iov_len = 1; int controlLength = CMSG_SPACE(sizeof(int)); byte *control = stackalloc byte[controlLength]; msghdr header = default(msghdr); header.msg_iov = &iov; header.msg_iovlen = 1; header.msg_control = control; header.msg_controllen = controlLength; cmsghdr *cmsg = CMSG_FIRSTHDR(&header); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); int *fdptr = (int *)CMSG_DATA(cmsg); * fdptr = acceptedFd; do { rv = sendmsg(toSocket, &header, MSG_NOSIGNAL); } while (rv < 0 && errno == EINTR); IOInterop.Close(acceptedFd); } return(PosixResult.FromReturnValue(rv)); }
public unsafe static PosixResult CompleteZeroCopy(int socket) { msghdr msg = default(msghdr); int controlLength = 100; byte * control = stackalloc byte[controlLength]; do { msg.msg_control = control; msg.msg_controllen = controlLength; ssize_t rv; do { rv = recvmsg(socket, &msg, MSG_NOSIGNAL | MSG_ERRQUEUE); } while (rv < 0 && errno == EINTR); if (rv == -1) { return(PosixResult.FromReturnValue(rv)); } cmsghdr *cm = CMSG_FIRSTHDR(&msg); if (cm == null) { continue; } if (!((cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_RECVERR) || (cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_RECVERR))) { continue; } sock_extended_err *serr = (sock_extended_err *)CMSG_DATA(cm); if ((serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) || (serr->ee_errno != 0)) { continue; } return(new PosixResult(((serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED) != 0) ? ZeroCopyCopied : ZeroCopySuccess)); } while (true); }