/// <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); }
/// <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; }
/// <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); }
/// <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); }
/// <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); }
/// <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; }
/// <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)); }
/// <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; }
/// <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); }
/// <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)); }
/// <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)); }
/// <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); }