From aa007a31303783ebfcf895d4192dd583e5edb583 Mon Sep 17 00:00:00 2001 From: Blitblank Date: Sat, 18 Jul 2026 14:43:36 -0500 Subject: [PATCH] cleanup a little bit --- client/src/TcpClient.cpp | 36 ++++++++---- server/src/TcpServer.cpp | 117 +++++++++++++++++++++++++-------------- 2 files changed, 98 insertions(+), 55 deletions(-) diff --git a/client/src/TcpClient.cpp b/client/src/TcpClient.cpp index 888483f..467365e 100644 --- a/client/src/TcpClient.cpp +++ b/client/src/TcpClient.cpp @@ -24,53 +24,65 @@ ErrorCode TcpClient::init() { logger_->log("TcpClient", LogFlag::Debug, "Initializing TcpClient..."); // keeping everything in here for now - int socketFd; + int socketFd; // file descriptor for the client socket (socket proper is a function) int sendBytes; int receiveBytes; char buffer[1024]; - struct hostent* host; - struct sockaddr_in serverAddress; - struct timeval timestamp; - struct timeval timestampEnd; + struct hostent* host; // houses host network info + struct sockaddr_in serverAddress; // ip address of the server socket + // parse the hostname string into uint8s host = gethostbyname(configuration_.hostname.c_str()); if(host == NULL) { logger_->log("TcpClient", LogFlag::Debug, "Unable to parse hostname."); + close(socketFd); // TODO: probably on a destructor return ErrorCode::Error; } + // create tcp socket socketFd = socket(AF_INET, SOCK_STREAM, 0); if(socketFd < 0) { logger_->log("TcpClient", LogFlag::Debug, "Unable to open client socket."); + close(socketFd); return ErrorCode::Error; } + // describe the server address from the hostname and port + memset(&serverAddress.sin_zero, 0, sizeof(serverAddress.sin_zero)); serverAddress.sin_family = AF_INET; serverAddress.sin_port = htons(configuration_.port); serverAddress.sin_addr = *((struct in_addr*)host->h_addr); - memset(&serverAddress.sin_zero, 0, sizeof(serverAddress.sin_zero)); + // connect to server if(connect(socketFd, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr)) < 0) { logger_->log("TcpClient", LogFlag::Debug, "Unable to connect to server."); + close(socketFd); return ErrorCode::Error; } + // send data buffer to server memset(buffer, 0x67, sizeof(buffer)); - gettimeofday(×tamp, NULL); - sendBytes = send(socketFd, buffer, sizeof(buffer), 0); if(sendBytes < 0) { - logger_->log("TcpClient", LogFlag::Debug, "Unable to send to server."); + logger_->log("TcpClient", LogFlag::Error, "Unable to send to server."); + close(socketFd); return ErrorCode::Error; } + logger_->log("TcpClient", LogFlag::Debug, "Sent {} bytes to the server.", sendBytes); - gettimeofday(×tampEnd, NULL); + // listen for receive from the server memset(buffer, 0x00, sizeof(buffer)); - receiveBytes = recv(socketFd, buffer, sizeof(buffer), 0); + receiveBytes = recv(socketFd, buffer, sizeof(buffer), 0); // TODO: this currently blocks forever, add timeout + + // we expect a response based on the server design, something went wrong otherwise if(receiveBytes < 0) { - logger_->log("TcpClient", LogFlag::Debug, "Unable to receive from server."); + logger_->log("TcpClient", LogFlag::Error, "Unable to receive from server."); + return ErrorCode::Error; + } else if(receiveBytes == 0) { + logger_->log("TcpClient", LogFlag::Error, "Server closed the connection during receive."); + close(socketFd); return ErrorCode::Error; } diff --git a/server/src/TcpServer.cpp b/server/src/TcpServer.cpp index 3b79d3a..b84881d 100644 --- a/server/src/TcpServer.cpp +++ b/server/src/TcpServer.cpp @@ -24,69 +24,100 @@ ErrorCode TcpServer::init() { logger_->log("TcpServer", LogFlag::Debug, "Initializing TcpServer..."); // keeping everything in here for now - int socketFd; - int clientFd; + int serverSocket; // file descriptor for the server's socket + int clientSocket; // file descriptor for the client's socket char buffer[1024]; int receiveBytes; int sendBytes; - struct sockaddr_in serverAddress; - struct sockaddr_in clientAddress; + struct sockaddr_in serverAddress; // ip address of the server + struct sockaddr_in clientAddress; // ip address of the client - socketFd = socket(AF_INET, SOCK_STREAM, 0); - if(socketFd < 0) { + serverSocket = socket(AF_INET, SOCK_STREAM, 0); // create the server's endpoint + // AF_INET: address-family: internet (alias for IPV4, AF_INET6 for ipv6) + // SOCK_STREAM: two-way handshaked communication + // 0: use the default protocol for the given domain/type (SOCK_STREAM=TCP and SOCK_DGRAM=UDP) + if(serverSocket < 0) { // error-check the socket creation logger_->log("TcpServer", LogFlag::Error, "Unable to open Server socket."); return ErrorCode::Error; } + // configure the socket int on = 1; - setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + // SOL_SOCKET: generic socket options family + // SO_REUSEADDR: allows the socket to bind to an idle port + // on: value to set the option to - serverAddress.sin_family = AF_INET; - serverAddress.sin_port = htons(configuration_.port); - serverAddress.sin_addr.s_addr = INADDR_ANY; - memset(&serverAddress.sin_zero, 0, sizeof(serverAddress.sin_zero)); + // describe the IP address of the server + memset(&serverAddress.sin_zero, 0, sizeof(serverAddress.sin_zero)); // sin_zero is padding that must be clear + serverAddress.sin_family = AF_INET; // socket-internet_family = ADDRESS_FAMILTY: INTERNET + serverAddress.sin_port = htons(configuration_.port); // socket-internet_port = our port (endianess checked) + serverAddress.sin_addr.s_addr = INADDR_ANY; // socket-address = 0.0.0.0 - if(bind(socketFd, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr)) < 0) { + // bind the server socket to the server's address + if(bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr)) < 0) { logger_->log("TcpServer", LogFlag::Error, "Unable to bind server socket."); return ErrorCode::Error; } - memset(buffer, 0x0, sizeof(buffer)); - listen(socketFd, 10); + // configure for listening + memset(buffer, 0x0, sizeof(buffer)); // clear our buffer so we know for sure any data in it is the client's + listen(serverSocket, 10); // configure the socket as a passive server with a fifo queue 10 requests long logger_->log("TcpServer", LogFlag::Debug, "Server listening on port {}...", configuration_.port); - unsigned int sinSize = sizeof(struct sockaddr); - clientFd = accept(socketFd, (struct sockaddr*)&clientAddress, &sinSize); - if(clientFd < 0) { - logger_->log("TcpServer", LogFlag::Error, "Unable to accept client socket."); - return ErrorCode::Error; + while(true) { + + // connnect to client when requested. successful connection creates the client socket + unsigned int clientAddressSize = sizeof(struct sockaddr); + clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressSize); + // accept() blocks until connected + // the sockaddr_in must be cast to the generic sockaddr struct + // accept() also writes the size of the incoming clientAddress + if(clientSocket < 0) { // error check that guy + logger_->log("TcpServer", LogFlag::Error, "Unable to accept client socket."); + // TODO: more robust errorchecking with errnos + return ErrorCode::Error; + } + logger_->log("TcpServer", LogFlag::Info + , "Client connected from {}:{}", + inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port)); + + // receive loop + while(1) { + // receive messages from the client. blocks until there's a message to receive + receiveBytes = recv(clientSocket, buffer, sizeof(buffer), 0); + // last arg is flags, 0=default + // MSG_PEEK: read without consuming the message from the queue + // MSG_WAITALL: block until all of the specified size is received + // MSG_DONTWAIT: non-blocking receive, returns -1 immediately if queue is empty + if(receiveBytes <= 0) break; // exit when there's nothing left to receive + + logger_->log("TcpClient", LogFlag::Debug, "Received {} bytes from client: 0x{:x}", receiveBytes, buffer[0]); + + // echo back received data back to the client + sendBytes = send(clientSocket, buffer, receiveBytes, 0); // TODO: send size is not guarenteed + if(sendBytes < 0) { + logger_->log("TcpServer", LogFlag::Error, "Unable to send to client."); + return ErrorCode::Error; + } + logger_->log("TcpClient", LogFlag::Debug, "Echoed {} bytes back to the client.", sendBytes); + + } // TODO: configure a sigevent to catch a process exit signal into manually exiting this while loop + // so resources can be properly cleaned up by destructors + + // error check receive + if(receiveBytes == 0) { + logger_->log("TcpClient", LogFlag::Info, "Client disconnected."); + } else if(receiveBytes < 0) { + logger_->log("TcpClient", LogFlag::Error, "Read from client failed."); + } + + close(clientSocket); + } - struct sockaddr_in peerAddress; - unsigned int len = sizeof(peerAddress); - char serverIp[20]; - logger_->log("TcpServer", LogFlag::Debug, "Accept socket... Client address: {} Port: {}", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port)); - getsockname(clientFd, (struct sockaddr*)&peerAddress, &len); - inet_ntop(AF_INET, &peerAddress, serverIp, sizeof(serverIp)); - logger_->log("TcpServer", LogFlag::Debug, "Accept socket... Server address: {}", serverIp); - - receiveBytes = recv(clientFd, buffer, sizeof(buffer), 0); - if(receiveBytes < 0) { - logger_->log("TcpServer", LogFlag::Error, "Unable to receive from client."); - return ErrorCode::Error; - } - logger_->log("TcpClient", LogFlag::Debug, "Received {} bytes from client: 0x{:x}", receiveBytes, buffer[2]); - - // echo back - sendBytes = send(clientFd, buffer, sizeof(buffer), 0); - if(sendBytes < 0) { - logger_->log("TcpServer", LogFlag::Error, "Unable to send to client."); - return ErrorCode::Error; - } - logger_->log("TcpClient", LogFlag::Debug, "Echoed {} bytes back to the client.", sendBytes); - - close(socketFd); + close(serverSocket); return ErrorCode::Success; }