コード例 #1
0
        /// <summary>
        /// Tries to initialize the Registered I/O handle.
        /// </summary>
        /// <param name="socket">A descriptor that identifies a socket.</param>
        /// <param name="result">Contains valid object if operation was successful, <c>null</c> otherwise.</param>
        /// <returns><c>true</c> if operation was successful, <c>false</c> otherwise.</returns>
        public static unsafe Boolean TryCreate(SOCKET socket, out RIOHandle result)
        {
            // get function table id
            var functionTableId = WinsockInterop.WSAID_MULTIPLE_RIO;

            // initialize functions table
            var functionTable = new RIO_EXTENSION_FUNCTION_TABLE();

            // get table size
            var tableSize = (UInt32)sizeof(RIO_EXTENSION_FUNCTION_TABLE);

            // will contain actual table size
            UInt32 actualTableSize;

            // try get registered IO functions table
            var tryGetTableResult = WinsockInterop.WSAIoctl(socket, WinsockInterop.SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &functionTableId, 16, &functionTable, tableSize, out actualTableSize, IntPtr.Zero, IntPtr.Zero);

            // check if attempt was successful
            if (tryGetTableResult == WinsockInterop.SOCKET_ERROR)
            {
                result = null;

                // return fail
                return(false);
            }

            // create registered I/O handle
            result = new RIOHandle(ref functionTable);

            // return success
            return(true);
        }
コード例 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TcpWorker" /> class.
        /// </summary>
        private TcpWorker(UIntPtr serverSocket, RIOHandle rioHandle, IocpWorker[] workers)
        {
            this.serverSocket = serverSocket;

            this.rioHandle = rioHandle;

            this.workers = workers;
        }
コード例 #3
0
ファイル: TcpWorker.cs プロジェクト: stas-sultanov/SXN.Net
		/// <summary>
		/// Initializes a new instance of the <see cref="TcpWorker" /> class.
		/// </summary>
		private TcpWorker(UIntPtr serverSocket, RIOHandle rioHandle, IocpWorker[] workers)
		{
			this.serverSocket = serverSocket;

			this.rioHandle = rioHandle;

			this.workers = workers;
		}
コード例 #4
0
ファイル: IocpWorker.cs プロジェクト: stas-sultanov/SXN.Net
        /// <summary>
        /// Initializes a new instance of the <see cref="IocpWorker" /> class.
        /// </summary>
        private IocpWorker(RIOHandle rioHandle, Int32 processorId, IntPtr completionPort, IntPtr completionQueue, RIOBufferPool bufferPool)
        {
            RioHandle = rioHandle;

            ProcessorId = processorId;

            CompletionPort = completionPort;

            CompletionQueue = completionQueue;

            // set buffer pool
            BufferPool = bufferPool;

            // initialize dictionary of the connections
            Connections = new ConcurrentDictionary <UInt64, TcpConnection>();

            thread = new Thread(Process);
        }
コード例 #5
0
ファイル: IocpWorker.cs プロジェクト: stas-sultanov/SXN.Net
		/// <summary>
		/// Initializes a new instance of the <see cref="IocpWorker" /> class.
		/// </summary>
		private IocpWorker(RIOHandle rioHandle, Int32 processorId, IntPtr completionPort, IntPtr completionQueue, RIOBufferPool bufferPool)
		{
			RioHandle = rioHandle;

			ProcessorId = processorId;

			CompletionPort = completionPort;

			CompletionQueue = completionQueue;

			// set buffer pool
			BufferPool = bufferPool;

			// initialize dictionary of the connections
			Connections = new ConcurrentDictionary<UInt64, TcpConnection>();

			thread = new Thread(Process);
		}
コード例 #6
0
        /// <summary>
        /// Tries to release all allocated resources.
        /// </summary>
        /// <param name="rioHandle">The object that provides work with Winsock registered I/O extensions.</param>
        /// <param name="kernelErrorCode">Contains <c>0</c> if operation was successful, error code otherwise.</param>
        /// <returns><c>true</c> if operation was successful, <c>false</c> otherwise.</returns>
        public unsafe Boolean TryRelease(RIOHandle rioHandle, out UInt32 kernelErrorCode)
        {
            // 0 deregister buffer with Registered I/O extension
            {
                rioHandle.DeregisterBuffer(bufferId);
            }

            // 1 try free memory
            {
                var freeResult = KernelInterop.VirtualFree((void *)buffer, 0, KernelInterop.MEM_RELEASE);

                if (freeResult == false)
                {
                    kernelErrorCode = KernelInterop.GetLastError();

                    return(false);
                }
            }

            // 2 success
            kernelErrorCode = 0;

            return(true);
        }
コード例 #7
0
ファイル: RIOHandle.cs プロジェクト: stas-sultanov/SXN.Net
		/// <summary>
		/// Tries to initialize the Registered I/O handle.
		/// </summary>
		/// <param name="socket">A descriptor that identifies a socket.</param>
		/// <param name="result">Contains valid object if operation was successful, <c>null</c> otherwise.</param>
		/// <returns><c>true</c> if operation was successful, <c>false</c> otherwise.</returns>
		public static unsafe Boolean TryCreate(SOCKET socket, out RIOHandle result)
		{
			// get function table id
			var functionTableId = WinsockInterop.WSAID_MULTIPLE_RIO;

			// initialize functions table
			var functionTable = new RIO_EXTENSION_FUNCTION_TABLE();

			// get table size
			var tableSize = (UInt32) sizeof(RIO_EXTENSION_FUNCTION_TABLE);

			// will contain actual table size
			UInt32 actualTableSize;

			// try get registered IO functions table
			var tryGetTableResult = WinsockInterop.WSAIoctl(socket, WinsockInterop.SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &functionTableId, 16, &functionTable, tableSize, out actualTableSize, IntPtr.Zero, IntPtr.Zero);

			// check if attempt was successful
			if (tryGetTableResult == WinsockInterop.SOCKET_ERROR)
			{
				result = null;

				// return fail
				return false;
			}

			// create registered I/O handle
			result = new RIOHandle(ref functionTable);

			// return success
			return true;
		}
コード例 #8
0
ファイル: IocpWorker.cs プロジェクト: stas-sultanov/SXN.Net
        /// <summary>
        /// Tries to create a new instance of the <see cref="IocpWorker" />.
        /// </summary>
        /// <param name="rioHandle">The object that provides work with Winsock registered I/O extensions.</param>
        /// <param name="processorIndex">The index of the processor.</param>
        /// <param name="segmentLength">The length of the segment.</param>
        /// <param name="segmentsCount">The count of the segments.</param>
        /// <returns>
        /// An instance of <see cref="TryResult{T}" /> which encapsulates result of the operation.
        /// <see cref="TryResult{T}.Success" /> contains <c>true</c> if operation was successful, <c>false</c> otherwise.
        /// <see cref="TryResult{T}.Result" /> contains valid object if operation was successful, <c>null</c> otherwise.
        /// </returns>
        public static unsafe TryResult <IocpWorker> TryCreate(RIOHandle rioHandle, Int32 processorIndex, UInt32 segmentLength, UInt32 segmentsCount)
        {
            #region 0 try create completion port

            var completionPort = KernelInterop.CreateIoCompletionPort(KernelInterop.INVALID_HANDLE_VALUE, IntPtr.Zero, UIntPtr.Zero, 0);

            // check if operation has succeed
            if (completionPort == IntPtr.Zero)
            {
                // get error code
                var kernelErrorCode = (KernelErrorCode)KernelInterop.GetLastError();

                // return fail result
                TryResult <IocpWorker> .CreateFail(kernelErrorCode);
            }

            #endregion

            #region 1 try create completion queue

            // compose completion method structure
            var completionMethod = new RIO_NOTIFICATION_COMPLETION
            {
                // set type to IOCP
                Type  = RIO_NOTIFICATION_COMPLETION_TYPE.RIO_IOCP_COMPLETION,
                union =
                {
                    // set IOCP parameters
                    Iocp              = new RIO_NOTIFICATION_COMPLETION.UNION.IOCP
                    {
                        // set completion port
                        IocpHandle    = completionPort,
                        // set completion key
                        CompletionKey = (UInt64)processorIndex,
                        Overlapped    = (NativeOverlapped *)-1
                    }
                }
            };

            // try create completion queue
            var completionQueue = rioHandle.CreateCompletionQueue(maxOutsandingCompletions, completionMethod);

            if (completionQueue == WinsockInterop.RIO_INVALID_CQ)
            {
                // get error code
                var winsockErrorCode = (WinsockErrorCode)WinsockInterop.WSAGetLastError();

                // return fail result
                TryResult <IocpWorker> .CreateFail(winsockErrorCode);
            }

            #endregion

            #region 2 try create buffer pool

            var tryCreateBufferPool = RIOBufferPool.TryCreate(rioHandle, segmentLength, segmentsCount);

            if (tryCreateBufferPool.Success == false)
            {
                // return result
                return(TryResult <IocpWorker> .CreateFail(tryCreateBufferPool.KernelErrorCode, tryCreateBufferPool.WinsockErrorCode));
            }

            #endregion

            // success
            var result = new IocpWorker(rioHandle, processorIndex, completionPort, completionQueue, tryCreateBufferPool.Result);

            // return success result
            return(TryResult <IocpWorker> .CreateSuccess(result));
        }
コード例 #9
0
		/// <summary>
		/// Tries to release all allocated resources.
		/// </summary>
		/// <param name="rioHandle">The object that provides work with Winsock registered I/O extensions.</param>
		/// <param name="kernelErrorCode">Contains <c>0</c> if operation was successful, error code otherwise.</param>
		/// <returns><c>true</c> if operation was successful, <c>false</c> otherwise.</returns>
		public unsafe Boolean TryRelease(RIOHandle rioHandle, out UInt32 kernelErrorCode)
		{
			// 0 deregister buffer with Registered I/O extension
			{
				rioHandle.DeregisterBuffer(bufferId);
			}

			// 1 try free memory
			{
				var freeResult = KernelInterop.VirtualFree((void*) buffer, 0, KernelInterop.MEM_RELEASE);

				if (freeResult == false)
				{
					kernelErrorCode = KernelInterop.GetLastError();

					return false;
				}
			}

			// 2 success
			kernelErrorCode = 0;

			return true;
		}
コード例 #10
0
		/// <summary>
		/// Tries to create a new instance of the <see cref="RIOBufferPool" />.
		/// </summary>
		/// <param name="rioHandle">The object that provides work with Winsock registered I/O extensions.</param>
		/// <param name="segmentLength">The length of the segment.</param>
		/// <param name="segmentsCount">The count of the segments.</param>
		/// <returns>
		/// An instance of <see cref="TryResult{T}" /> which encapsulates result of the operation.
		/// <see cref="TryResult{T}.Success" /> contains <c>true</c> if operation was successful, <c>false</c> otherwise.
		/// <see cref="TryResult{T}.Result" /> contains valid object if operation was successful, <c>null</c> otherwise.
		/// </returns>
		/// <remarks>
		/// The multiplication of <paramref name="segmentLength" /> and <paramref name="segmentsCount" /> must produce value that is aligned to Memory Allocation Granularity.
		/// </remarks>
		public static unsafe TryResult<RIOBufferPool> TryCreate(RIOHandle rioHandle, UInt32 segmentLength, UInt32 segmentsCount)
		{
			// calculate size of the memory buffer to allocate
			var bufferLength = segmentLength * segmentsCount;

			void* memoryPointer;

			IntPtr buffer;

			IntPtr bufferId;

			// 1 try allocate memory block
			{
				// try reserve and commit memory block
				memoryPointer = KernelInterop.VirtualAlloc(null, bufferLength, KernelInterop.MEM_COMMIT | KernelInterop.MEM_RESERVE, KernelInterop.PAGE_READWRITE);

				// check if allocation has failed
				if (memoryPointer == null)
				{
					// get kernel error code
					var kernelErrorCode = (KernelErrorCode) KernelInterop.GetLastError();

					// return result
					return TryResult<RIOBufferPool>.CreateFail(kernelErrorCode);
				}

				// set buffer
				buffer = (IntPtr) memoryPointer;
			}

			// 2 try register buffer with Registered I/O extensions
			{
				bufferId = rioHandle.RegisterBuffer(buffer, bufferLength);

				if (bufferId == WinsockInterop.RIO_INVALID_BUFFERID)
				{
					// get winsock error code
					var winsockErrorCode = (WinsockErrorCode) WinsockInterop.WSAGetLastError();

					// free allocated memory
					var freeResult = KernelInterop.VirtualFree(memoryPointer, 0, KernelInterop.MEM_RELEASE);

					// set kernel error code
					if (freeResult)
					{
						// return result
						return TryResult<RIOBufferPool>.CreateFail(winsockErrorCode);
					}

					// get kernel error code
					var kernelErrorCode = (KernelErrorCode) KernelInterop.GetLastError();

					// return result
					return TryResult<RIOBufferPool>.CreateFail(kernelErrorCode, winsockErrorCode);
				}
			}

			// 3 success
			var result = new RIOBufferPool(buffer, bufferLength, bufferId, segmentLength, segmentsCount);

			// return result
			return TryResult<RIOBufferPool>.CreateSuccess(result);
		}
コード例 #11
0
        /// <summary>
        /// Tries to create a new instance of the <see cref="RIOBufferPool" />.
        /// </summary>
        /// <param name="rioHandle">The object that provides work with Winsock registered I/O extensions.</param>
        /// <param name="segmentLength">The length of the segment.</param>
        /// <param name="segmentsCount">The count of the segments.</param>
        /// <returns>
        /// An instance of <see cref="TryResult{T}" /> which encapsulates result of the operation.
        /// <see cref="TryResult{T}.Success" /> contains <c>true</c> if operation was successful, <c>false</c> otherwise.
        /// <see cref="TryResult{T}.Result" /> contains valid object if operation was successful, <c>null</c> otherwise.
        /// </returns>
        /// <remarks>
        /// The multiplication of <paramref name="segmentLength" /> and <paramref name="segmentsCount" /> must produce value that is aligned to Memory Allocation Granularity.
        /// </remarks>
        public static unsafe TryResult <RIOBufferPool> TryCreate(RIOHandle rioHandle, UInt32 segmentLength, UInt32 segmentsCount)
        {
            // calculate size of the memory buffer to allocate
            var bufferLength = segmentLength * segmentsCount;

            void *memoryPointer;

            IntPtr buffer;

            IntPtr bufferId;

            // 1 try allocate memory block
            {
                // try reserve and commit memory block
                memoryPointer = KernelInterop.VirtualAlloc(null, bufferLength, KernelInterop.MEM_COMMIT | KernelInterop.MEM_RESERVE, KernelInterop.PAGE_READWRITE);

                // check if allocation has failed
                if (memoryPointer == null)
                {
                    // get kernel error code
                    var kernelErrorCode = (KernelErrorCode)KernelInterop.GetLastError();

                    // return result
                    return(TryResult <RIOBufferPool> .CreateFail(kernelErrorCode));
                }

                // set buffer
                buffer = (IntPtr)memoryPointer;
            }

            // 2 try register buffer with Registered I/O extensions
            {
                bufferId = rioHandle.RegisterBuffer(buffer, bufferLength);

                if (bufferId == WinsockInterop.RIO_INVALID_BUFFERID)
                {
                    // get winsock error code
                    var winsockErrorCode = (WinsockErrorCode)WinsockInterop.WSAGetLastError();

                    // free allocated memory
                    var freeResult = KernelInterop.VirtualFree(memoryPointer, 0, KernelInterop.MEM_RELEASE);

                    // set kernel error code
                    if (freeResult)
                    {
                        // return result
                        return(TryResult <RIOBufferPool> .CreateFail(winsockErrorCode));
                    }

                    // get kernel error code
                    var kernelErrorCode = (KernelErrorCode)KernelInterop.GetLastError();

                    // return result
                    return(TryResult <RIOBufferPool> .CreateFail(kernelErrorCode, winsockErrorCode));
                }
            }

            // 3 success
            var result = new RIOBufferPool(buffer, bufferLength, bufferId, segmentLength, segmentsCount);

            // return result
            return(TryResult <RIOBufferPool> .CreateSuccess(result));
        }
コード例 #12
0
        /// <summary>
        /// Activates server.
        /// </summary>
        public static TryResult <TcpWorker> TryInitialize(TcpServerSettings settings)
        {
            // 0 try initiates use of the Winsock DLL by a process
            {
                WSADATA data;

                var startupResultCode = WinsockInterop.WSAStartup(WinsockInterop.Version, out data);

                // check if startup was successful
                if (startupResultCode != WinsockErrorCode.None)
                {
                    return(TryResult <TcpWorker> .CreateFail(startupResultCode));
                }
            }

            // 1 try create server socket
            SOCKET serverSocket;

            {
                serverSocket = WinsockInterop.WSASocket(WinsockInterop.AF_INET, (Int32)SocketType.Stream, (Int32)ProtocolType.Tcp, IntPtr.Zero, 0, WinsockInterop.WSA_FLAG_REGISTERED_IO);

                // check if socket created
                if (WinsockInterop.INVALID_SOCKET == serverSocket)
                {
                    goto FAIL;
                }
            }

            // 2 try initialize Registered I/O extension
            RIOHandle rioHandle;

            if (!RIOHandle.TryCreate(serverSocket, out rioHandle))
            {
                goto FAIL;
            }

            // 3 get count of processors
            var processorsCount = Environment.ProcessorCount;

            // 4 create collection of the IOCP workers
            var workers = new IocpWorker[processorsCount];

            // initialize workers
            for (var processorIndex = 0; processorIndex < processorsCount; processorIndex++)
            {
                // try create worker
                var tryCreateWorker = IocpWorker.TryCreate(rioHandle, processorIndex, 4096, 1024);

                // check if operation has succeed
                if (!tryCreateWorker.Success)
                {
                    goto FAIL;
                }

                // add to collection
                workers[processorIndex] = tryCreateWorker.Result;
            }

            // try configure server socket and start listen
            if (!TryConfigureBindAndStartListen(serverSocket, settings))
            {
                goto FAIL;
            }

            // success
            var server = new TcpWorker(serverSocket, rioHandle, workers);

            foreach (var worker in workers)
            {
                worker.thread.Start();
            }

            return(TryResult <TcpWorker> .CreateSuccess(server));

FAIL:

            // get last error
            var errorCode = (WinsockErrorCode)WinsockInterop.WSAGetLastError();

            // terminate use of the Winsock DLL
            WinsockInterop.WSACleanup();

            // return fail
            return(TryResult <TcpWorker> .CreateFail(errorCode));
        }
コード例 #13
0
ファイル: IocpWorker.cs プロジェクト: stas-sultanov/SXN.Net
		/// <summary>
		/// Tries to create a new instance of the <see cref="IocpWorker" />.
		/// </summary>
		/// <param name="rioHandle">The object that provides work with Winsock registered I/O extensions.</param>
		/// <param name="processorIndex">The index of the processor.</param>
		/// <param name="segmentLength">The length of the segment.</param>
		/// <param name="segmentsCount">The count of the segments.</param>
		/// <returns>
		/// An instance of <see cref="TryResult{T}" /> which encapsulates result of the operation.
		/// <see cref="TryResult{T}.Success" /> contains <c>true</c> if operation was successful, <c>false</c> otherwise.
		/// <see cref="TryResult{T}.Result" /> contains valid object if operation was successful, <c>null</c> otherwise.
		/// </returns>
		public static unsafe TryResult<IocpWorker> TryCreate(RIOHandle rioHandle, Int32 processorIndex, UInt32 segmentLength, UInt32 segmentsCount)
		{
			#region 0 try create completion port

			var completionPort = KernelInterop.CreateIoCompletionPort(KernelInterop.INVALID_HANDLE_VALUE, IntPtr.Zero, UIntPtr.Zero, 0);

			// check if operation has succeed
			if (completionPort == IntPtr.Zero)
			{
				// get error code
				var kernelErrorCode = (KernelErrorCode) KernelInterop.GetLastError();

				// return fail result
				TryResult<IocpWorker>.CreateFail(kernelErrorCode);
			}

			#endregion

			#region 1 try create completion queue

			// compose completion method structure
			var completionMethod = new RIO_NOTIFICATION_COMPLETION
			{
				// set type to IOCP
				Type = RIO_NOTIFICATION_COMPLETION_TYPE.RIO_IOCP_COMPLETION,
				union =
				{
					// set IOCP parameters
					Iocp = new RIO_NOTIFICATION_COMPLETION.UNION.IOCP
					{
						// set completion port
						IocpHandle = completionPort,
						// set completion key
						CompletionKey = (UInt64) processorIndex,
						Overlapped = (NativeOverlapped*) -1
					}
				}
			};

			// try create completion queue
			var completionQueue = rioHandle.CreateCompletionQueue(maxOutsandingCompletions, completionMethod);

			if (completionQueue == WinsockInterop.RIO_INVALID_CQ)
			{
				// get error code
				var winsockErrorCode = (WinsockErrorCode) WinsockInterop.WSAGetLastError();

				// return fail result
				TryResult<IocpWorker>.CreateFail(winsockErrorCode);
			}

			#endregion

			#region 2 try create buffer pool

			var tryCreateBufferPool = RIOBufferPool.TryCreate(rioHandle, segmentLength, segmentsCount);

			if (tryCreateBufferPool.Success == false)
			{
				// return result
				return TryResult<IocpWorker>.CreateFail(tryCreateBufferPool.KernelErrorCode, tryCreateBufferPool.WinsockErrorCode);
			}

			#endregion

			// success
			var result = new IocpWorker(rioHandle, processorIndex, completionPort, completionQueue, tryCreateBufferPool.Result);

			// return success result
			return TryResult<IocpWorker>.CreateSuccess(result);
		}