X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsocketengine_iocp.cpp;h=9070f4d495c7f52ee01e3ddc72cfb25b1e0af070;hb=30a17a7034a5afce1094479628408a0903c62e17;hp=947b518b67a3d164a8d3fa1e09a497a644ab10c9;hpb=6ab38d48cad06633bfe5a118c1c5a6877fba6d5a;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/socketengine_iocp.cpp b/src/socketengine_iocp.cpp index 947b518b6..9070f4d49 100644 --- a/src/socketengine_iocp.cpp +++ b/src/socketengine_iocp.cpp @@ -9,276 +9,276 @@ * the file COPYING for details. * * --------------------------------------------------- - */ - -#include "socketengine_iocp.h" -#include -#include - -IOCPEngine::IOCPEngine(InspIRCd * Instance) : SocketEngine(Instance) -{ - // Create completion port - m_completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)0, 0); - - // Null variables out. - CurrentSetSize = 0; - EngineHandle = 0; - memset(ref, 0, sizeof(EventHandler*) * MAX_DESCRIPTORS); -} - -IOCPEngine::~IOCPEngine() -{ - CloseHandle(m_completionPort); -}; - -bool IOCPEngine::AddFd(EventHandler* eh) -{ - int fake_fd = GenerateFd(); - int is_accept = 0; - int opt_len = sizeof(int); - if(fake_fd < 0) - return false; - - // are we a listen socket? - getsockopt(eh->GetFd(), SOL_SOCKET, SO_ACCEPTCONN, (char*)&is_accept, &opt_len); - - // set up the read event so the socket can actually receive data :P - eh->m_internalFd = fake_fd; - eh->m_writeEvent = 0; - eh->m_acceptEvent = 0; - - // assign the socket to the completion port - if(!CreateIoCompletionPort((HANDLE)eh->GetFd(), m_completionPort, (ULONG_PTR)eh->m_internalFd, 0)) - return false; - - // set up binding, increase set size - ref[fake_fd] = eh; - ++CurrentSetSize; - - // setup initial events - if(is_accept) - PostAcceptEvent(eh); - else - PostReadEvent(eh); - - // log message - ServerInstance->Log(DEBUG, "New fake fd: %u, real fd: %u, address 0x%p", fake_fd, eh->GetFd(), eh); - - // post a write event if there is data to be written - if(eh->Writeable()) - WantWrite(eh); - - // we're all good =) - m_binding.insert( map::value_type( eh->GetFd(), eh ) ); - return true; -} - -bool IOCPEngine::DelFd(EventHandler* eh, bool force /* = false */) -{ - int fake_fd = eh->m_internalFd; - int fd = eh->GetFd(); - - if(ref[fake_fd] == 0) - return false; - - ServerInstance->Log(DEBUG, "Removing fake fd %u, real fd %u, address 0x%p", fake_fd, eh->GetFd(), eh); - - // Cancel pending i/o operations. - assert(CancelIo((HANDLE)fd) == TRUE); - - // Free the buffer, and delete the event. - if(eh->m_readEvent != 0) - delete ((Overlapped*)eh->m_readEvent); - - if(eh->m_writeEvent != 0) - delete ((Overlapped*)eh->m_writeEvent); - - if(eh->m_acceptEvent != 0) - { - delete ((accept_overlap*)((Overlapped*)eh->m_acceptEvent)->m_params); - delete ((Overlapped*)eh->m_acceptEvent); - } - - // Clear binding - ref[fake_fd] = 0; - m_binding.erase(eh->GetFd()); - - // decrement set size - --CurrentSetSize; - - // success - return true; -} - -void IOCPEngine::WantWrite(EventHandler* eh) -{ - // Post event - write begin - if(!eh->m_writeEvent) - { - Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_WRITE_READY, 0); - eh->m_writeEvent = (void*)ov; - PostQueuedCompletionStatus(m_completionPort, 0, (ULONG_PTR)eh->m_internalFd, &ov->m_overlap); - } -} - -bool IOCPEngine::PostCompletionEvent(EventHandler * eh, SocketIOEvent type, int param) -{ - Overlapped * ov = new Overlapped(type, param); - return PostQueuedCompletionStatus(m_completionPort, 0, (ULONG_PTR)eh->m_internalFd, &ov->m_overlap); -} - -void IOCPEngine::PostReadEvent(EventHandler * eh) -{ - Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_READ_READY, 0); - DWORD flags = 0; - DWORD r_length = 0; - WSABUF buf; - - // by passing a null buffer pointer, we can have this working in the same way as epoll.. - // its slower, but it saves modifying all network code. - buf.buf = 0; - buf.len = 0; - - // determine socket type. - DWORD sock_type; - int sock_len = sizeof(DWORD); - if(getsockopt(eh->GetFd(), SOL_SOCKET, SO_TYPE, (char*)&sock_type, &sock_len) == -1) - { - // wtfhax? - PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0); - delete ov; - return; - } - switch(sock_type) - { - case SOCK_DGRAM: // UDP Socket - { - if(WSARecvFrom(eh->GetFd(), &buf, 1, &r_length, &flags, 0, 0, &ov->m_overlap, 0)) - { - int err = WSAGetLastError(); - if(WSAGetLastError() != WSA_IO_PENDING) - { - delete ov; - PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0); - return; - } - } - }break; - - case SOCK_STREAM: // TCP Socket - { - if(WSARecv(eh->GetFd(), &buf, 1, &r_length, &flags, &ov->m_overlap, 0) == SOCKET_ERROR) - { - if(WSAGetLastError() != WSA_IO_PENDING) - { - delete ov; - PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0); - return; - } - } - }break; - - default: - { - printf("unknwon socket type: %u\n", sock_type); - assert(false); - }break; - } - eh->m_readEvent = (void*)ov; -} - -int IOCPEngine::DispatchEvents() -{ - DWORD len; - LPOVERLAPPED overlap; - Overlapped * ov; - EventHandler * eh; - int intfd; - int ret; - unsigned long bytes_recv; - - while(GetQueuedCompletionStatus(m_completionPort, &len, (PULONG_PTR)&intfd, &overlap, 100)) - { - // woot, we got an event on a socket :P - eh = ref[intfd]; - ov = CONTAINING_RECORD(overlap, Overlapped, m_overlap); - if(eh == 0) continue; - switch(ov->m_event) - { - case SOCKET_IO_EVENT_WRITE_READY: - { - eh->m_writeEvent = 0; - eh->HandleEvent(EVENT_WRITE, 0); - }break; - - case SOCKET_IO_EVENT_READ_READY: - { - ret = ioctlsocket(eh->GetFd(), FIONREAD, &bytes_recv); - eh->m_readEvent = 0; - if(ret != 0 || bytes_recv == 0) - { - // end of file - PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, EIO); - } - else - { - eh->HandleEvent(EVENT_READ, 0); - PostReadEvent(eh); - } - }break; - - case SOCKET_IO_EVENT_ACCEPT: - { - /* this is kinda messy.. :/ */ - eh->HandleEvent(EVENT_READ, ov->m_params); - delete ((accept_overlap*)ov->m_params); - eh->m_acceptEvent = 0; - PostAcceptEvent(eh); - }break; - - case SOCKET_IO_EVENT_ERROR: - { - eh->HandleEvent(EVENT_ERROR, ov->m_params); - }break; - } - - delete ov; - } - - return 0; -} - -void IOCPEngine::PostAcceptEvent(EventHandler * eh) -{ - int fd = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, WSA_FLAG_OVERLAPPED); - int len = sizeof(sockaddr_in) + 16; - DWORD dwBytes; - accept_overlap * ao = new accept_overlap; - memset(ao->buf, 0, 1024); - ao->socket = fd; - - Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_ACCEPT, (int)ao); - eh->m_acceptEvent = (void*)ov; - - if(AcceptEx(eh->GetFd(), fd, ao->buf, 0, len, len, &dwBytes, &ov->m_overlap) == FALSE) - { - int err = WSAGetLastError(); - if(err != WSA_IO_PENDING) - { - printf("PostAcceptEvent err: %d\n", err); - } - } -} - - -std::string IOCPEngine::GetName() -{ - return "iocp"; -} - -int __accept_socket(SOCKET s, sockaddr * addr, int * addrlen, void * acceptevent) -{ - Overlapped * ovl = (Overlapped*)acceptevent; + */ + +#include "socketengine_iocp.h" +#include + +IOCPEngine::IOCPEngine(InspIRCd * Instance) : SocketEngine(Instance) +{ + // Create completion port + m_completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)0, 0); + + // Null variables out. + CurrentSetSize = 0; + EngineHandle = 0; + memset(ref, 0, sizeof(EventHandler*) * MAX_DESCRIPTORS); +} + +IOCPEngine::~IOCPEngine() +{ + CloseHandle(m_completionPort); +} + +bool IOCPEngine::AddFd(EventHandler* eh) +{ + int fake_fd = GenerateFd(); + int is_accept = 0; + int opt_len = sizeof(int); + if(fake_fd < 0) + return false; + + // are we a listen socket? + getsockopt(eh->GetFd(), SOL_SOCKET, SO_ACCEPTCONN, (char*)&is_accept, &opt_len); + + // set up the read event so the socket can actually receive data :P + eh->m_internalFd = fake_fd; + eh->m_writeEvent = 0; + eh->m_acceptEvent = 0; + + // assign the socket to the completion port + if(!CreateIoCompletionPort((HANDLE)eh->GetFd(), m_completionPort, (ULONG_PTR)eh->m_internalFd, 0)) + return false; + + // set up binding, increase set size + ref[fake_fd] = eh; + ++CurrentSetSize; + + // setup initial events + if(is_accept) + PostAcceptEvent(eh); + else + PostReadEvent(eh); + + // log message + ServerInstance->Log(DEBUG, "New fake fd: %u, real fd: %u, address 0x%p", fake_fd, eh->GetFd(), eh); + + // post a write event if there is data to be written + if(eh->Writeable()) + WantWrite(eh); + + // we're all good =) + m_binding.insert( map::value_type( eh->GetFd(), eh ) ); + return true; +} + +bool IOCPEngine::DelFd(EventHandler* eh, bool force /* = false */) +{ + int fake_fd = eh->m_internalFd; + int fd = eh->GetFd(); + + if(ref[fake_fd] == 0) + return false; + + ServerInstance->Log(DEBUG, "Removing fake fd %u, real fd %u, address 0x%p", fake_fd, eh->GetFd(), eh); + + // Cancel pending i/o operations. + if (CancelIo((HANDLE)fd) == FALSE) + return false; + + // Free the buffer, and delete the event. + if(eh->m_readEvent != 0) + delete ((Overlapped*)eh->m_readEvent); + + if(eh->m_writeEvent != 0) + delete ((Overlapped*)eh->m_writeEvent); + + if(eh->m_acceptEvent != 0) + { + delete ((accept_overlap*)((Overlapped*)eh->m_acceptEvent)->m_params); + delete ((Overlapped*)eh->m_acceptEvent); + } + + // Clear binding + ref[fake_fd] = 0; + m_binding.erase(eh->GetFd()); + + // decrement set size + --CurrentSetSize; + + // success + return true; +} + +void IOCPEngine::WantWrite(EventHandler* eh) +{ + // Post event - write begin + if(!eh->m_writeEvent) + { + Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_WRITE_READY, 0); + eh->m_writeEvent = (void*)ov; + PostQueuedCompletionStatus(m_completionPort, 0, (ULONG_PTR)eh->m_internalFd, &ov->m_overlap); + } +} + +bool IOCPEngine::PostCompletionEvent(EventHandler * eh, SocketIOEvent type, int param) +{ + Overlapped * ov = new Overlapped(type, param); + return PostQueuedCompletionStatus(m_completionPort, 0, (ULONG_PTR)eh->m_internalFd, &ov->m_overlap); +} + +void IOCPEngine::PostReadEvent(EventHandler * eh) +{ + Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_READ_READY, 0); + DWORD flags = 0; + DWORD r_length = 0; + WSABUF buf; + + // by passing a null buffer pointer, we can have this working in the same way as epoll.. + // its slower, but it saves modifying all network code. + buf.buf = 0; + buf.len = 0; + + // determine socket type. + DWORD sock_type; + int sock_len = sizeof(DWORD); + if(getsockopt(eh->GetFd(), SOL_SOCKET, SO_TYPE, (char*)&sock_type, &sock_len) == -1) + { + // wtfhax? + PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0); + delete ov; + return; + } + switch(sock_type) + { + case SOCK_DGRAM: // UDP Socket + { + if(WSARecvFrom(eh->GetFd(), &buf, 1, &r_length, &flags, 0, 0, &ov->m_overlap, 0)) + { + int err = WSAGetLastError(); + if(WSAGetLastError() != WSA_IO_PENDING) + { + delete ov; + PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0); + return; + } + } + }break; + + case SOCK_STREAM: // TCP Socket + { + if(WSARecv(eh->GetFd(), &buf, 1, &r_length, &flags, &ov->m_overlap, 0) == SOCKET_ERROR) + { + if(WSAGetLastError() != WSA_IO_PENDING) + { + delete ov; + PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0); + return; + } + } + }break; + + default: + { + printf("unknwon socket type: %u\n", sock_type); + return; + }break; + } + eh->m_readEvent = (void*)ov; +} + +int IOCPEngine::DispatchEvents() +{ + DWORD len; + LPOVERLAPPED overlap; + Overlapped * ov; + EventHandler * eh; + int intfd; + int ret; + unsigned long bytes_recv; + + while(GetQueuedCompletionStatus(m_completionPort, &len, (PULONG_PTR)&intfd, &overlap, 100)) + { + // woot, we got an event on a socket :P + eh = ref[intfd]; + ov = CONTAINING_RECORD(overlap, Overlapped, m_overlap); + if(eh == 0) continue; + switch(ov->m_event) + { + case SOCKET_IO_EVENT_WRITE_READY: + { + eh->m_writeEvent = 0; + eh->HandleEvent(EVENT_WRITE, 0); + }break; + + case SOCKET_IO_EVENT_READ_READY: + { + ret = ioctlsocket(eh->GetFd(), FIONREAD, &bytes_recv); + eh->m_readEvent = 0; + if(ret != 0 || bytes_recv == 0) + { + // end of file + PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, EIO); + } + else + { + eh->HandleEvent(EVENT_READ, 0); + PostReadEvent(eh); + } + }break; + + case SOCKET_IO_EVENT_ACCEPT: + { + /* this is kinda messy.. :/ */ + eh->HandleEvent(EVENT_READ, ov->m_params); + delete ((accept_overlap*)ov->m_params); + eh->m_acceptEvent = 0; + PostAcceptEvent(eh); + }break; + + case SOCKET_IO_EVENT_ERROR: + { + eh->HandleEvent(EVENT_ERROR, ov->m_params); + }break; + } + + delete ov; + } + + return 0; +} + +void IOCPEngine::PostAcceptEvent(EventHandler * eh) +{ + int fd = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, WSA_FLAG_OVERLAPPED); + int len = sizeof(sockaddr_in) + 16; + DWORD dwBytes; + accept_overlap * ao = new accept_overlap; + memset(ao->buf, 0, 1024); + ao->socket = fd; + + Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_ACCEPT, (int)ao); + eh->m_acceptEvent = (void*)ov; + + if(AcceptEx(eh->GetFd(), fd, ao->buf, 0, len, len, &dwBytes, &ov->m_overlap) == FALSE) + { + int err = WSAGetLastError(); + if(err != WSA_IO_PENDING) + { + printf("PostAcceptEvent err: %d\n", err); + } + } +} + + +std::string IOCPEngine::GetName() +{ + return "iocp"; +} + +int __accept_socket(SOCKET s, sockaddr * addr, int * addrlen, void * acceptevent) +{ + Overlapped * ovl = (Overlapped*)acceptevent; accept_overlap * ov = (accept_overlap*)ovl->m_params; sockaddr_in * server_address = (sockaddr_in*)&ov->buf[10]; @@ -292,7 +292,7 @@ int __accept_socket(SOCKET s, sockaddr * addr, int * addrlen, void * acceptevent int __getsockname(SOCKET s, sockaddr * name, int * namelen, void * acceptevent) { - Overlapped * ovl = (Overlapped*)acceptevent; + Overlapped * ovl = (Overlapped*)acceptevent; accept_overlap * ov = (accept_overlap*)ovl->m_params; sockaddr_in * server_address = (sockaddr_in*)&ov->buf[10];