Probleme IOCP Queue bleibt hängen mit WRK Penetration Tool



  • Moin habe in meine Libnetplus das den Windows support hinzugefügt funktioniert auch leider nicht wenn ich mit dem wrk Tool um die 10000 Anfragen stelle dann friert die Queue ohne Meldung ein das Programm läuft weiter aber kann aber keine neuen Anfragen stellen:

    Der Komplette Source code:
    https://tuxist.de/git/jan.koester/libnetplus

    Das Project mit dem ich getestet (httpsysinfo) habe:

    https://tuxist.de/git/jan.koester/libhttppp/-/tree/master/examples?ref_type=heads

    Der Event Code:

    /*******************************************************************************
    Copyright (c) 2014, Jan Koester jan.koester@gmx.net
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    	* Redistributions of source code must retain the above copyright
    	  notice, this list of conditions and the following disclaimer.
    	* Redistributions in binary form must reproduce the above copyright
    	  notice, this list of conditions and the following disclaimer in the
    	  documentation and/or other materials provided with the distribution.
    	* Neither the name of the <organization> nor the
    	  names of its contributors may be used to endorse or promote products
    	  derived from this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *******************************************************************************/
    
    #include <iostream>
    #include <algorithm>
    #include <chrono>
    #include <memory>
    #include <mutex>
    #include <cstring>
    
    #include <signal.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    #include <winsock2.h>
    #include <ws2ipdef.h>
    #include <mswsock.h>
    #include <strsafe.h>
    
    #include <errno.h>
    
    #include "socket.h"
    #include "exception.h"
    #include "eventapi.h"
    #include "connection.h"
    #include <assert.h>
    
    #define READEVENT 0
    #define SENDEVENT 1
    
    #define BLOCKSIZE 16384
    
    namespace netplus {
    
    	enum IOState {
    		IO_READ_STATE = 0,
    		IO_WRITE_STATE = 1,
    		IO_CLOSE_STATE = 2
    	};
    
    	class client {
    	public:
    		client(eventapi* eapi) : api(eapi), State(IO_READ_STATE), CurCon(nullptr) {
    			api->CreateConnetion(&CurCon);
    		}
    
    		~client() {
    			if (CurCon) {
    				api->deleteConnetion(CurCon);
    			}
    		}
    
    		int                State;
    		eventapi*          api;
    		con*               CurCon;
    		mutable std::mutex cltmtx;
    	};
    
    	class poll {
    	public:
    
    		poll(HANDLE iocp, eventapi* api, socket* ssock)
    			: g_iocp(iocp), g_eventapi(api), g_serversocket(ssock) {}
    
    		void AddToClientList(client* pClientContext) {
    			std::lock_guard<std::mutex> lock(g_ClientContextMutex);
    			g_ClientContext.push_back(pClientContext);
    		}
    
    		void AssociateWithIOCP(client* pClientContext) {
    			//Associate the socket with IOCP
    			HANDLE giocp2 = CreateIoCompletionPort((HANDLE)(pClientContext)->CurCon->csock->fd(), g_iocp, (ULONG_PTR)pClientContext, 0);
    
    			if (!giocp2 || g_iocp != giocp2) {
    				DWORD err = GetLastError();
    				NetException exp;
    				exp[NetException::Error] << "AssociateWithIOCP fehlgeschlagen: Fehlercode " << err;
    				throw exp;
    			}
    		}
    
    		void RemoveFromClientList(client* pClientContext) {
    			std::lock_guard<std::mutex> lock(g_ClientContextMutex);
    			auto it = std::find(g_ClientContext.begin(), g_ClientContext.end(), pClientContext);
    			if (it != g_ClientContext.end()) {
    				g_ClientContext.erase(it);
    				delete pClientContext;
    			}
    		}
    
    		void AcceptConnection(LPFN_ACCEPTEX lpfnAcceptEx, int tid, ULONG_PTR args) {
    			client* pClientContext = new client(g_eventapi);
    
    			if (g_serversocket->_Type == TCP)
    				pClientContext->CurCon->csock = new tcp();
    
    			try {
    				g_serversocket->accept(lpfnAcceptEx, pClientContext->CurCon->csock);
    
    				pClientContext->CurCon->csock->setNonBlock();
    
    				//Store this object
    				AddToClientList(pClientContext);
    
    				AssociateWithIOCP(pClientContext);
    			} catch (NetException& e) {
    				delete pClientContext->CurCon->csock;
    				RemoveFromClientList(pClientContext);
    				throw e;
    			}
    			g_eventapi->ConnectEvent(pClientContext->CurCon, tid, args);
    
    			try {
    				size_t recv = pClientContext->CurCon->csock->recvData(nullptr, 0, 0);
    
    				WSAResetEvent(pClientContext->CurCon->csock->_Overlapped.hEvent);
    
    			} catch (NetException& e) {
    				std::cerr << e.what() << std::endl;
    				if (e.getErrorType() != NetException::Note)
    					throw e;
    			}
    
    
    		}
    
    	private:
    		HANDLE               g_iocp;
    		socket*              g_serversocket;
    		eventapi*            g_eventapi;
    		std::vector<client*> g_ClientContext;
    		std::mutex           g_ClientContextMutex; // NEU: mutex als Member
    		friend class         client;
    		friend class         EventWorker;
    	};
    
    	void eventapi::RequestEvent(con* curcon, const int tid, ULONG_PTR args) {
    		//dummy
    	};
    
    	void eventapi::ResponseEvent(con* curcon, const int tid, ULONG_PTR args) {
    		//dummy
    	};
    
    	void eventapi::ConnectEvent(con* curcon, const int tid, ULONG_PTR args) {
    		//dummy
    	};
    
    	void eventapi::DisconnectEvent(con* curcon, const int tid, ULONG_PTR args) {
    		//dummy
    	};
    
    	void eventapi::CreateConnetion(con** curcon) {
    		*curcon = new con(this);
    	};
    
    	void eventapi::deleteConnetion(con* curcon) {
    		delete curcon;
    	};
    
    	event::event(socket* serversocket, int timeout) {
    		if (!serversocket) {
    			NetException exp;
    			exp[NetException::Critical] << "server socket empty!";
    			throw exp;
    		}
    		_Timeout = timeout;
    		_ServerSocket = serversocket;
    		_ServerSocket->setNonBlock();
    		_ServerSocket->bind();
    		_ServerSocket->listen();
    
    		SYSTEM_INFO sysinfo;
    		GetSystemInfo(&sysinfo);
    		threads = sysinfo.dwNumberOfProcessors;
    	}
    
    	event::~event() {
    	}
    
    
    	class EventWorkerArgs {
    	public:
    		EventWorkerArgs() {
    		}
    
    		EventWorkerArgs(const EventWorkerArgs& eargs) {
    			event = eargs.event;
    			eviocp = eargs.eviocp;
    			evpoll = eargs.evpoll;
    			ssocket = eargs.ssocket;
    			timeout = eargs.timeout;
    			args = eargs.args;
    		}
    
    
    		int         timeout;
    		HANDLE      eviocp;
    		poll* evpoll;
    		eventapi* event;
    		socket* ssocket;
    		void* args;
    	};
    
    	class EventWorker {
    	public:
    		EventWorker(int tid, ULONG_PTR args, EventWorkerArgs* eargs) {
    			for (;;) {
    				ULONG_PTR   lpContext = 0;
    				OVERLAPPED* pOverlapped = nullptr;
    				DWORD       dwBytesTransfered = 0;
    
    				bool bReturn = GetQueuedCompletionStatus(
    					eargs->eviocp,
    					&dwBytesTransfered,
    					&lpContext,
    					&pOverlapped,
    					WSA_INFINITE);
    
    				if (lpContext == 0) {
    					continue;
    				}
    
    				client* pClientContext = (client*)lpContext;
    
    				if (!bReturn && dwBytesTransfered == 0) {
    					eargs->evpoll->RemoveFromClientList(pClientContext);
    					continue;
    				}
    
    				try {
    					auto& curCon = pClientContext->CurCon;
    
    					switch (pClientContext->State) {
    						case IO_WRITE_STATE: {
    							std::lock_guard<std::mutex> lock(pClientContext->cltmtx);
    							eargs->event->ResponseEvent(curCon, tid, args);
    
    							ULONG ssize = curCon->SendData.size() < BLOCKSIZE ? (ULONG)curCon->SendData.size() : BLOCKSIZE;
    							DWORD ret = 0;
    							ret = curCon->csock->sendData(curCon->SendData.data(), ssize, 0);
    							curCon->SendData.resize(ret);
    							if (curCon->SendData.empty())
    								pClientContext->State = IO_READ_STATE;
    						}break;
    						case IO_READ_STATE: {
    							std::lock_guard<std::mutex> lock(pClientContext->cltmtx);
    							std::shared_ptr<char[]> buf(new char[BLOCKSIZE], std::default_delete<char[]>());
    							size_t recv = curCon->csock->recvData(buf.get(), BLOCKSIZE, 0);
    							curCon->RecvData.append(buf.get(), recv);
    
    							eargs->event->RequestEvent(curCon, tid, args);
    							if (!curCon->SendData.empty())
    								pClientContext->State = IO_WRITE_STATE;
    						}break;
    						case IO_CLOSE_STATE: {
    							WSACloseEvent(pClientContext->CurCon->csock->_Overlapped.hEvent);
    							eargs->evpoll->RemoveFromClientList(pClientContext);
    						}continue;
    					}
    					WSAResetEvent(pClientContext->CurCon->csock->_Overlapped.hEvent);
    				} catch (NetException& e) {
    					std::cerr << e.what() << std::endl;
    					if (e.getErrorType() != NetException::Note) {
    						pClientContext->State = IO_CLOSE_STATE;
    						continue;
    					}
    				} catch (...) {
    					std::cerr << "unknown error close coonection !" << std::endl;
    					pClientContext->State = IO_CLOSE_STATE;
    					continue;
    				}
    				
    			} // for
    		}
    	};
    
    
    
    	void event::runEventloop(ULONG_PTR args) {
    		NetException exception;
    		EventWorkerArgs eargs;
    
    		HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
    
    		if (!iocp) {
    			NetException exp;
    			exp[NetException::Critical] << "event: runEventloop couldn't create iocp !";
    			throw exp;
    		}
    
    		LPFN_ACCEPTEX lpfnAcceptEx = NULL;
    		GUID GuidAcceptEx = WSAID_ACCEPTEX;
    		WSAOVERLAPPED olOverlap;
    		DWORD dwBytes;
    
    		memset(&olOverlap, 0, sizeof(olOverlap));
    
    		poll evpoll(iocp, this, _ServerSocket);
    
    		eargs.ssocket = _ServerSocket;
    		eargs.event = this;
    		eargs.evpoll = &evpoll;
    		eargs.timeout = _Timeout;
    		eargs.eviocp = iocp;
    
    		std::vector <std::thread> threadpool;
    
    		for (int i = 0; i < threads; i++) {
    			try {
    				threadpool.push_back(std::thread([&eargs, args, i] {
    					EventWorker(i, args, &eargs);
    					}));
    			}
    			catch (NetException& e) {
    				throw e;
    			}
    		}
    
    		int iResult = WSAIoctl(_ServerSocket->fd(), SIO_GET_EXTENSION_FUNCTION_POINTER,
    			&GuidAcceptEx, sizeof(GuidAcceptEx),
    			&lpfnAcceptEx, sizeof(lpfnAcceptEx),
    			&dwBytes, NULL, NULL);
    
    		if (iResult == SOCKET_ERROR) {
    			NetException exp;
    			exp[NetException::Critical] << "WSAIoctl failed with error: " << WSAGetLastError();
    			closesocket(_ServerSocket->fd());
    			WSACleanup();
    			throw exp;
    		}
    
    		WSAEVENT g_hAcceptEvent = WSACreateEvent();
    		WSANETWORKEVENTS WSAEvents;
    
    		if (WSA_INVALID_EVENT == g_hAcceptEvent) {
    			NetException exp;
    			exp[NetException::Error] << "Error occurred while WSACreateEvent().";
    			throw exp;
    		}
    
    		if (SOCKET_ERROR == WSAEventSelect(_ServerSocket->fd(), g_hAcceptEvent, FD_ACCEPT | FD_READ | FD_WRITE)) {
    			NetException exp;
    			exp[NetException::Error] << "Error occurred while WSAEventSelect().";
    			WSACloseEvent(g_hAcceptEvent);
    			throw exp;
    		}
    
    		for (;;) {
    			if (WSA_WAIT_FAILED != WSAWaitForMultipleEvents(1, &g_hAcceptEvent, FALSE, WSA_INFINITE, FALSE)) {
    				WSAEnumNetworkEvents(_ServerSocket->fd(), g_hAcceptEvent, &WSAEvents);
    				if ((WSAEvents.lNetworkEvents & FD_ACCEPT) && (0 == WSAEvents.iErrorCode[FD_ACCEPT_BIT])) {
    					try {
    						evpoll.AcceptConnection(lpfnAcceptEx,0, args);
    					} catch (NetException& e) {
    						std::cerr << e.what() << std::endl;
    					}
    				}
    			}
    		}
    
    		for (auto i = threadpool.begin(); i != threadpool.end(); ++i) {
    			i->join();
    		}
    	}
    };
    


  • @Tuxist1 sagte in Probleme IOCP Queue bleibt hängen mit WRK Penetration Tool:

    Moin habe in meine Libnetplus das den Windows support hinzugefügt funktioniert auch leider nicht wenn ich mit dem wrk Tool um die 10000 Anfragen stelle dann friert die Queue ohne Meldung ein das Programm läuft weiter aber kann aber keine neuen Anfragen stellen:

    Sorry, aber was willst du damit sagen? Ich verstehe da gerade gar nichts.



  • @Quiche-Lorraine wrk ist ein Benchmarktool für Httprequests bringt leider meine iocp layer ins straucheln so das er nicht mehr antwortet hatte schon Vermutung das was mit den Sockets zu tun hat.



  • geht jetzt werde noch bißchen weiter testen.

    		void RemoveFromClientList(client* pClientContext) {
    			std::lock_guard<std::mutex> lock(g_ClientContextMutex);
    			auto it = std::find(g_ClientContext.begin(), g_ClientContext.end(), pClientContext);
    			if (it != g_ClientContext.end()) {
    				if (pClientContext->cltmtx.try_lock()) {
    					pClientContext->cltmtx.unlock();
    					g_ClientContext.erase(it);
    				}				
    			}
    		}
    


  • @Tuxist1 sagte in Probleme IOCP Queue bleibt hängen mit WRK Penetration Tool:

    wrk ist ein Benchmarktool für Httprequests bringt leider meine iocp layer ins straucheln so das er nicht mehr antwortet hatte schon Vermutung das was mit den Sockets zu tun hat.

    Sorry wenn ich das mal sage. Aber dein Schreibstil ist mir zu hektisch.

    Ich vermute mal dass du einen Belastungstest durchgeführt hast und dadurch dein Code hängenbleibt.

    Ein paar Punkte:

    • Dein komplettes Klassendesign gefällt mir nicht. Du nutzt sehr viele Pointer. Gerade in Sachen Threading ist dies nicht sinnvoll, da Verantwortlichkeiten nicht geklärt sind. Wer darf z.B. auf client->api zugreifen? Ist dieser Zugriff Thread Safe? Generell versuche ich für jeden Thread die Daten so lokal wie möglich zu halten.

    • Warum nutzt du manuelle Speicherverwaltung? So etwas ist fehleranfällig und unnötig.

    • Achte bitte strikt auf Rückgabewerte. Folgender Code sieht strange aus:

    bool bReturn = GetQueuedCompletionStatus(
    	eargs->eviocp,
    	&dwBytesTransfered,
    	&lpContext,
    	&pOverlapped,
    	WSA_INFINITE);
    // Annahme bReturn ist false, dann darf die Funktion GetQueuedCompletionStatus
    // nach deinem Code pOverlapped nicht verändern. Kannst du das garantieren?
    if (lpContext == 0) {
    	continue;
    }
    client* pClientContext = (client*)lpContext;
    if (!bReturn && dwBytesTransfered == 0) {  // Gibt es auch den Zustand dass bReturn false ist, aber dwBytesTransfered > 0?
    	eargs->evpoll->RemoveFromClientList(pClientContext);
    	continue;
    }
    
    • Ich würde dir auch empfehlen Logging zu nutzen. Beachte bitte aber dass Logging das Verhalten beeinflusst, da die Ausgabe ein paar Millisekunden fressen wird.


  • es wird noch ominöser haben jetzt auf anderen Rechner getestet mit Windows 11 Enterprise 24H2 der hat keine Probleme nur der mit Windows 11 IOT Enterprise 25H1 der schließt aus irgendeinem Grund keine Sockets habe ich durchs Logging heraus gefunden. Hat jemand eine Idee über die mögliche Ursache ?



  • ich glaube ich habe die Lösung der virtio win netzwerk treiber scheint fehlerhaft zu sein.



  • Finde es gut, dass du den ruppigen Beitrag von Quiche ignoriert hast



  • @Tuxist1 sagte in Probleme IOCP Queue bleibt hängen mit WRK Penetration Tool:

    es wird noch ominöser haben jetzt auf anderen Rechner getestet mit Windows 11 Enterprise 24H2 der hat keine Probleme nur der mit Windows 11 IOT Enterprise 25H1 der schließt aus irgendeinem Grund keine Sockets habe ich durchs Logging heraus gefunden. Hat jemand eine Idee über die mögliche Ursache ?

    Was sagt der Rückgabewert von closesocket() bzw. WSAGetLastError?


Anmelden zum Antworten