Пример #1
0
        void OnPollServer(Poll handle, PollStatus status)
        {
            Socket socket       = this.serverContext.Socket.Accept();
            IntPtr socketHandle = TestHelper.GetHandle(socket);

            const PollMask Mask = PollMask.Readable | PollMask.Writable | PollMask.Disconnect;
            Poll           poll = this.loop
                                  .CreatePoll(socketHandle)
                                  .Start(Mask, this.OnPollConnection);

            Timer timer   = this.loop.CreateTimer();
            var   context = new ConnectionContext(socket, poll, true)
            {
                TimerHandle = timer,
                EventMask   = Mask,
                OpenHandles = 2
            };

            timer.UserToken = context;
            poll.UserToken  = context;

            this.serverContext.ConnectionCount++;
            if (this.serverContext.ConnectionCount < NumberOfClients)
            {
                return;
            }

            DestroyServerContext(this.serverContext);
        }
Пример #2
0
        void StartClient()
        {
            var socket      = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            var anyEndPoint = new IPEndPoint(IPAddress.Loopback, IPEndPoint.MinPort);

            socket.Bind(anyEndPoint);

            IntPtr         handle = TestHelper.GetHandle(socket);
            const PollMask Mask   = PollMask.Readable | PollMask.Writable | PollMask.Disconnect;
            Poll           poll   = this.loop.CreatePoll(handle).Start(Mask, this.OnPollConnection);

            Timer timer   = this.loop.CreateTimer();
            var   context = new ConnectionContext(socket, poll, false)
            {
                TimerHandle = timer,
                EventMask   = Mask,
                OpenHandles = 2
            };

            timer.UserToken = context;
            poll.UserToken  = context;

            // Kick off the connect
            try
            {
                socket.Connect(this.endPoint);
            }
            catch (SocketException exception)
            {
                if (!IsErrorAgain(exception))
                {
                    throw;
                }
            }
        }
Пример #3
0
        // Calling uv_poll_start() on a handle that is already active is fine.
        // Doing so will update the events mask that is being watched for.
        internal static void PollStart(IntPtr handle, PollMask mask)
        {
            Debug.Assert(handle != IntPtr.Zero);

            int result = uv_poll_start(handle, (int)mask, Poll.PollCallback);

            ThrowIfError(result);
        }
Пример #4
0
        /// <summary>
        ///     SOCKETFUNCTION implementation.
        /// </summary>
        /// <param name="easy"></param>
        /// <param name="sockfd"></param>
        /// <param name="what"></param>
        /// <param name="userp"></param>
        /// <param name="socketp"></param>
        /// <returns></returns>
        private int HandleSocket(IntPtr easy, IntPtr sockfd, CURLpoll what, IntPtr userp, IntPtr socketp)
        {
            Logger.LogTrace(
                $"Called {nameof(CURLMoption.SOCKETFUNCTION)}. We need to poll for {what} on socket {sockfd}.");

            switch (what)
            {
            case CURLpoll.IN:
            case CURLpoll.OUT:
            case CURLpoll.INOUT:
//#if !UNITY
                PollMask events = 0;

                if (what != CURLpoll.IN)
                {
                    events |= PollMask.Writable;
                }
                if (what != CURLpoll.OUT)
                {
                    events |= PollMask.Readable;
                }

                Logger.LogTrace($"Polling socket {sockfd} using libuv with mask {events}.");

                _socketMap.GetOrCreatePoll(sockfd, _loop).Start(events, (poll, status) =>
                {
                    CURLcselect flags = 0;

                    if (status.Mask.HasFlag(PollMask.Readable))
                    {
                        flags |= CURLcselect.IN;
                    }
                    if (status.Mask.HasFlag(PollMask.Writable))
                    {
                        flags |= CURLcselect.OUT;
                    }

                    Logger.LogTrace($"Finished polling socket {sockfd}.");
                    CurlNative.Multi.SocketAction(_multiHandle, sockfd, flags, out int _);
                    CheckMultiInfo();
                });
                break;

            case CURLpoll.REMOVE:
                Logger.LogTrace($"Removing poll of socket {sockfd}.");
                _socketMap.RemovePoll(sockfd);
                break;

//#else
//                    break;
//#endif
            default:
                throw new ArgumentOutOfRangeException(nameof(what));
            }
            return(0);
        }
Пример #5
0
        public Poll Start(PollMask eventMask, Action <Poll, PollStatus> callback)
        {
            Contract.Requires(callback != null);

            this.Validate();
            this.pollCallback = callback;
            NativeMethods.PollStart(this.InternalHandle, eventMask);

            return(this);
        }
Пример #6
0
        // Calling uv_poll_start() on a handle that is already active is fine.
        // Doing so will update the events mask that is being watched for.
        internal static void PollStart(IntPtr handle, PollMask mask)
        {
            Contract.Requires(handle != IntPtr.Zero);

            int result = uv_poll_start(handle, (int)mask, Poll.PollCallback);

            if (result < 0)
            {
                throw CreateError((uv_err_code)result);
            }
        }
Пример #7
0
        public Poll Start(PollMask eventMask, Action <Poll, PollStatus> callback)
        {
            if (callback is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.callback);
            }

            Validate();
            _pollCallback = callback;
            NativeMethods.PollStart(InternalHandle, eventMask);

            return(this);
        }
Пример #8
0
 internal PollStatus(PollMask mask, Exception error)
 {
     this.Mask  = mask;
     this.Error = error;
 }
Пример #9
0
        void OnPollConnection(Poll handle, PollStatus status)
        {
            var context = (ConnectionContext)handle.UserToken;

            PollMask pollMask  = status.Mask;
            PollMask newEvents = context.EventMask;
            var      random    = new Random(10);

            if ((pollMask & PollMask.Readable) == PollMask.Readable)
            {
                int action = random.Next() % 7;

                if (action == 0 ||
                    action == 1)
                {
                    // Read a couple of bytes.
                    var buffer = new byte[74];
                    int count  = TryReceive(context.Socket, buffer);
                    if (count > 0)
                    {
                        context.Receive += count;
                    }
                    else
                    {
                        // Got FIN.
                        context.ReceiveFinished = true;
                        newEvents &= ~PollMask.Readable;
                    }
                }
                else if (action == 2 ||
                         action == 3)
                {
                    // Read until EAGAIN.
                    var buffer = new byte[931];
                    int count  = TryReceive(context.Socket, buffer);
                    while (count > 0)
                    {
                        context.Receive += count;
                        count            = TryReceive(context.Socket, buffer);
                    }

                    if (count == 0)
                    {
                        // Got FIN.
                        context.ReceiveFinished = true;
                        newEvents &= ~PollMask.Readable;
                    }
                }
                else if (action == 4)
                {
                    // Ignore.
                }
                else if (action == 5)
                {
                    // Stop reading for a while. Restart in timer callback.
                    newEvents &= ~PollMask.Readable;

                    if (!context.TimerHandle.IsActive)
                    {
                        context.DelayedEventMask = PollMask.Readable;
                        context.TimerHandle.Start(this.OnTimerDelay, 10, 0);
                    }
                    else
                    {
                        context.DelayedEventMask |= PollMask.Readable;
                    }
                }
                else if (action == 6)
                {
                    // Fudge with the event mask.
                    context.PollHandle.Start(PollMask.Writable, this.OnPollConnection);
                    context.PollHandle.Start(PollMask.Readable, this.OnPollConnection);
                    context.EventMask = PollMask.Readable;
                }
            }

            if ((pollMask & PollMask.Writable) == PollMask.Writable &&
                !this.deplux && context.IsServerConnection)
            {
                // We have to send more bytes.
                int action = random.Next() % 7;

                if (action == 0 ||
                    action == 1)
                {
                    // Send a couple of bytes.
                    var buffer = new byte[103];

                    int send  = Math.Min(TransferBytes - context.Sent, buffer.Length);
                    int count = TrySend(context.Socket, buffer, send);
                    if (count < 0)
                    {
                        this.spuriousWritableWakeups++;
                    }
                    else
                    {
                        context.Sent += count;
                        this.validWritableWakeups++;
                    }
                }
                else if (action == 2 ||
                         action == 3)
                {
                    // Send until EAGAIN.
                    var buffer = new byte[1234];
                    int send   = Math.Min(TransferBytes - context.Sent, buffer.Length);
                    int count  = TrySend(context.Socket, buffer, send);
                    if (count < 0)
                    {
                        this.spuriousWritableWakeups++;
                    }
                    else
                    {
                        context.Sent += count;
                        this.validWritableWakeups++;
                    }

                    while (context.Sent < TransferBytes)
                    {
                        send  = Math.Min(TransferBytes - context.Sent, buffer.Length);
                        count = TrySend(context.Socket, buffer, send);
                        if (count < 0)
                        {
                            break;
                        }
                        else
                        {
                            context.Sent += count;
                        }
                    }
                }
                else if (action == 4)
                {
                    // Ignore.
                }
                else if (action == 5)
                {
                    // Stop sending for a while. Restart in timer callback.
                    newEvents &= ~PollMask.Writable;
                    if (!context.TimerHandle.IsActive)
                    {
                        context.DelayedEventMask = PollMask.Writable;
                        context.TimerHandle.Start(this.OnTimerDelay, 100, 0);
                    }
                    else
                    {
                        context.DelayedEventMask |= PollMask.Writable;
                    }
                }
                else if (action == 6)
                {
                    // Fudge with the event mask.
                    context.PollHandle.Start(PollMask.Readable, this.OnPollConnection);
                    context.PollHandle.Start(PollMask.Writable, this.OnPollConnection);
                    context.EventMask = PollMask.Writable;
                }
            }
            else
            {
                // Nothing more to write. Send FIN.
                context.Socket.Shutdown(SocketShutdown.Send);
                context.SentFinished = true;
                newEvents           &= ~PollMask.Writable;
            }

            if ((pollMask & PollMask.Disconnect) == PollMask.Disconnect)
            {
                context.Disconnected = true;
                newEvents           &= ~PollMask.Disconnect;
            }

            if (context.SentFinished ||
                context.ReceiveFinished ||
                context.Disconnected)
            {
                if (context.SentFinished ||
                    context.ReceiveFinished)
                {
                    this.DestroyConnectionContext(context);
                }
                else
                {
                    /* Poll mask changed. Call uv_poll_start again. */
                    context.EventMask = newEvents;
                    context.PollHandle.Start(newEvents, this.OnPollConnection);
                }
            }
        }
Пример #10
0
 internal PollStatus(PollMask mask, Exception error)
 {
     Mask  = mask;
     Error = error;
 }