diff --git a/Makefile b/Makefile index 0ea09bc..963ebee 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,7 @@ install: @mkdir -p $(INCLUDEDIR)/language/ @mkdir -p $(INCLUDEDIR)/fs/ @cp source/utils/*.h $(INCLUDEDIR)/utils/ + @cp source/utils/*.hpp $(INCLUDEDIR)/utils/ @cp source/system/*.h $(INCLUDEDIR)/system/ @cp source/language/*.h $(INCLUDEDIR)/language/ @cp source/fs/*.h $(INCLUDEDIR)/fs/ diff --git a/source/utils/TCPServer.cpp b/source/utils/TCPServer.cpp new file mode 100644 index 0000000..c24fcbb --- /dev/null +++ b/source/utils/TCPServer.cpp @@ -0,0 +1,130 @@ +#include "TCPServer.hpp" +#include +#include +#include +#include + +#include "logger.h" +#include "net.h" + +#define wiiu_errno (*__gh_errno_ptr()) + +TCPServer::TCPServer(s32 port,s32 priority) { + this->port = port; + this->sockfd = -1; + this->clientfd = -1; + memset(&(this->sock_addr),0,sizeof(this->sock_addr)); + + pThread = CThread::create(TCPServer::DoTCPThread, (void*)this, CThread::eAttributeAffCore2,priority); + pThread->resumeThread(); +} + +TCPServer::~TCPServer() { + CloseSockets(); + DEBUG_FUNCTION_LINE("Thread will be closed\n"); + exitThread = 1; + + ICInvalidateRange((void*)&exitThread, 4); + DCFlushRange((void*)&exitThread, 4); + + if(pThread != NULL) { + DEBUG_FUNCTION_LINE("Deleting it!\n"); + delete pThread; + } + DEBUG_FUNCTION_LINE("Thread done\n"); + pThread = NULL; +} + +void TCPServer::CloseSockets() { + if (this->sockfd != -1) { + socketclose(this->sockfd); + } + if (this->clientfd != -1) { + socketclose(this->clientfd); + } + this->sockfd = -1; + this->clientfd = -1; +} + +void TCPServer::ErrorHandling() { + CloseSockets(); + os_usleep(1000*1000*2); +} + +void TCPServer::DoTCPThreadInternal() { + s32 ret; + s32 len; + connected = false; + while (1) { + if(exitThread) { + break; + } + memset(&(this->sock_addr),0,sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = this->port; + sock_addr.sin_addr.s_addr = 0; + + this->sockfd = ret = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(ret == -1) { + ErrorHandling(); + continue; + } + s32 enable = 1; + + setsockopt(this->sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); + + ret = bind(this->sockfd, (sockaddr *)&sock_addr, 16); + if(ret < 0) { + ErrorHandling(); + continue; + } + ret = listen(this->sockfd, 1); + if(ret < 0) { + ErrorHandling(); + continue; + } + + do { + DEBUG_FUNCTION_LINE("Waiting for a connection\n"); + if(exitThread) { + break; + } + len = 16; + clientfd = ret = accept(sockfd, (sockaddr *)&(sock_addr), &len); + + if(ret == -1) { + ErrorHandling(); + break; + } + + if(!acceptConnection()) { + ErrorHandling(); + break; + } + + connected = true; + + DEBUG_FUNCTION_LINE("Connection accepted\n"); + + whileLoop(); + + DEBUG_FUNCTION_LINE("Client disconnected\n"); + + if(clientfd != -1) { + socketclose(clientfd); + } + clientfd = -1; + } while(0); + DEBUG_FUNCTION_LINE("Closing TCPServer\n"); + connected = false; + onConnectionClosed(); + CloseSockets(); + continue; + } + DEBUG_FUNCTION_LINE("Ending DoTCPThreadInternal\n"); +} + +void TCPServer::DoTCPThread(CThread *thread, void *arg) { + TCPServer * args = (TCPServer * )arg; + return args->DoTCPThreadInternal(); +} diff --git a/source/utils/TCPServer.hpp b/source/utils/TCPServer.hpp new file mode 100644 index 0000000..b832ffb --- /dev/null +++ b/source/utils/TCPServer.hpp @@ -0,0 +1,61 @@ +#ifndef _TCPSERVER_H_ +#define _TCPSERVER_H_ + +#include +#include +#include + +class TCPServer { +public: + TCPServer(s32 port, s32 priority); + virtual ~TCPServer(); + + bool isConnected() { + return connected; + } +protected: + bool shouldExit() { + return (exitThread == 1); + } + + s32 getClientFD() { + return clientfd; + } + + s32 getSocketFD() { + return sockfd; + } + + struct sockaddr_in getSockAddr() { + return sock_addr; + } +private: + virtual void CloseSockets(); + virtual void ErrorHandling(); + + static void DoTCPThread(CThread *thread, void *arg); + virtual void DoTCPThreadInternal(); + + virtual bool acceptConnection() = 0; + + virtual void onConnectionClosed(){ + DEBUG_FUNCTION_LINE("Default onConnectionClosed \n"); + } + + /** + Called when a connection has be accepted. + **/ + virtual bool whileLoop() = 0; + + struct sockaddr_in sock_addr; + volatile s32 sockfd = -1; + volatile s32 clientfd = -1; + + s32 port = 0; + volatile bool connected = false; + + volatile s32 exitThread = 0; + CThread *pThread = NULL; +}; + +#endif //_TCPSERVER_H_ diff --git a/source/utils/net.c b/source/utils/net.c index 01e5eab..30532de 100644 --- a/source/utils/net.c +++ b/source/utils/net.c @@ -1,20 +1,81 @@ -#include "dynamic_libs/socket_functions.h" +#include "net.h" +#include +#include -int recvwait(int sock, unsigned char *buffer, int len) -{ - int recvBytes = 0; +static volatile int socket_lock __attribute__((section(".data"))) = 0; - while(len) - { - int ret = recv(sock, buffer, len, 0); - if(ret <= 0) { +s32 recvwait(s32 sock, void *buffer, s32 len) { + while(socket_lock) { + os_usleep(1000); + } + s32 ret; + while (len > 0) { + ret = recv(sock, buffer, len, 0); + if(ret < 0) { + socket_lock = 0; return ret; } - len -= ret; - buffer += ret; - recvBytes += ret; + buffer = (void *)(((char *) buffer) + ret); } - - return recvBytes; + socket_lock = 0; + return 0; +} + +u8 recvbyte(s32 sock) { + unsigned char buffer[1]; + s32 ret; + + ret = recvwait(sock, buffer, 1); + if (ret < 0) return ret; + return buffer[0]; +} + +u32 recvword(s32 sock) { + u32 result; + s32 ret; + + ret = recvwait(sock, &result, 4); + if (ret < 0) return ret; + return result; +} + +s32 checkbyte(s32 sock) { + while(socket_lock) { + os_usleep(1000); + } + unsigned char buffer[1]; + s32 ret; + + ret = recv(sock, buffer, 1, MSG_DONTWAIT); + socket_lock = 0; + if (ret < 0) return ret; + if (ret == 0) return -1; + return buffer[0]; +} + +s32 sendwait(s32 sock, const void *buffer, s32 len) { + while(socket_lock) { + os_usleep(1000); + } + s32 ret; + while (len > 0) { + // For some reason the send blocks/crashes if the buffer is too big.. + int cur_length = len <= 0x30 ? len : 0x30; + ret = send(sock, buffer, cur_length, 0); + if(ret < 0) { + socket_lock = 0; + return ret; + } + len -= ret; + buffer = (void *)(((char *) buffer) + ret); + } + socket_lock = 0; + return 0; +} + +s32 sendbyte(s32 sock, unsigned char byte) { + unsigned char buffer[1]; + buffer[0] = byte; + return sendwait(sock, buffer, 1); } diff --git a/source/utils/net.h b/source/utils/net.h index 9f543c3..3d648b0 100644 --- a/source/utils/net.h +++ b/source/utils/net.h @@ -1,11 +1,18 @@ -#ifndef __NET_H_ -#define __NET_H_ +#ifndef _UTILS_NET_H_ +#define _UTILS_NET_H_ + +#include #ifdef __cplusplus extern "C" { #endif -int recvwait(int sock, unsigned char *buffer, int len); +s32 recvwait(s32 sock, void *buffer, s32 len); +u8 recvbyte(s32 sock); +u32 recvword(s32 sock); +s32 checkbyte(s32 sock); +s32 sendwait(s32 sock, const void *buffer, s32 len); +s32 sendbyte(s32 sock, unsigned char byte); #ifdef __cplusplus }