Exemplo n.º 1
0
        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;
        }
Exemplo n.º 2
0
        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);
                    }
                }
        }
Exemplo n.º 3
0
        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));
        }
Exemplo n.º 4
0
        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); }
Exemplo n.º 5
0
        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));
        }
Exemplo n.º 6
0
        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);
        }